diff --git a/docs-internal/registry-parity-worklist.md b/docs-internal/registry-parity-worklist.md index 48055a4d65..2b9883875c 100644 --- a/docs-internal/registry-parity-worklist.md +++ b/docs-internal/registry-parity-worklist.md @@ -106,7 +106,7 @@ actual backing: | **git** | TODO | our hand-rolled git from `sha1`+`flate2` | **real git** (upstream C), patched for WASI — **NOT gitoxide** | | **fd** | TODO | our `secureexec-fd` on raw `regex` (not sharkdp/fd) | real **fd** (sharkdp) | | **findutils** (`find`,`xargs`) | TODO | our hand-rolled on `regex`/shims | real GNU findutils, or `uutils/findutils` | -| **tree** | TODO | our hand-rolled, zero deps | real `tree`, or an established one | +| **tree** | DONE | our hand-rolled, zero deps | real `tree`, or an established one | | **grep** | TODO | our `secureexec-grep` on raw `regex` (**not** an established grep pkg) | **real GNU grep**, or a popular established grep (ripgrep's `grep` crates) | | **zip** | DONE | our 203-line `zip.c` over zlib/minizip (not Info-ZIP) | real Info-ZIP, or an established lib's CLI | | **unzip** | DONE | our 669-line `unzip.c` over zlib/minizip | real Info-ZIP unzip | @@ -188,9 +188,28 @@ works (`wasi-spawn` broker), so `xargs` is not a blocker. test client**, not an HTTP fetcher; real curl covers GET. But it's imported by `packages/shell` and is the client in cross-runtime network tests — migrate those dependents first, then drop the command. -- **tree — easy.** Real `tree` (Steve Baker) is a tiny plain-`Makefile` C program; - compile its `.c` directly against the sysroot. Pure readdir/stat — no - sockets/threads/spawn. +- **tree — DONE.** Replaced the custom Rust `secureexec-tree`/`cmd-tree` crates + with upstream Steve Baker `tree` 2.3.2 from `OldManProgrammer/unix-tree`. + It builds as a C toolchain command from pinned source, stages into + `@agentos-software/tree`, and refreshes the tracked runtime-core fallback + command. Sysroot fixes live one layer down: install `` and provide + deterministic missing-group lookup stubs so upstream `-g` support links + without a tree-source WASI branch. Proof: upstream source inspection in + `2026-07-08T05-13-50-0700-tree-fetch-upstream-2.3.2-inspect.log`; sysroot + patch check passes in + `2026-07-08T05-18-16-0700-tree-wasi-libc-patch-check-group-lookup-fixed.log`; + Makefile build passes in + `2026-07-08T05-20-02-0700-tree-upstream-make-build.log`; package build and + check-types pass in + `2026-07-08T05-21-08-0700-tree-package-build-upstream-after-install.log` and + `2026-07-08T05-21-08-0700-tree-check-types-upstream-after-install.log`; e2e + tree tests pass 6/6 in + `2026-07-08T05-29-45-0700-tree-vitest-upstream-final.log`; aggregate C + `programs` builds 58 commands in + `2026-07-08T05-30-44-0700-tree-make-programs-final.log`; Cargo metadata no + longer includes the deleted Rust tree crates in + `2026-07-08T05-33-17-0700-tree-cargo-metadata-after-removing-empty-dirs.log`. + Rev: `kpmrwxln` — `fix(tree): build upstream tree`. - **fd — moderate.** Swap `cmd-fd` to depend on real `fd-find` (like coreutils→`uu_*`; `fd-lock` is already patched). Only real issue: the parallel `ignore`/crossbeam walker needs the **serial-thread patch** (uu_sort pattern). diff --git a/packages/runtime-core/commands/tree b/packages/runtime-core/commands/tree old mode 100644 new mode 100755 index 49e9c7c18d..811c63e5fd Binary files a/packages/runtime-core/commands/tree and b/packages/runtime-core/commands/tree differ diff --git a/software/tree/bin/tree b/software/tree/bin/tree old mode 100644 new mode 100755 index 49e9c7c18d..811c63e5fd Binary files a/software/tree/bin/tree and b/software/tree/bin/tree differ diff --git a/software/tree/native/crates/cmd-tree/Cargo.toml b/software/tree/native/crates/cmd-tree/Cargo.toml deleted file mode 100644 index e85593575d..0000000000 --- a/software/tree/native/crates/cmd-tree/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -workspace = "../../../../../toolchain" -name = "cmd-tree" -version.workspace = true -edition.workspace = true -license.workspace = true -description = "tree standalone binary for secure-exec VM" - -[[bin]] -name = "tree" -path = "src/main.rs" - -[dependencies] -secureexec-tree = { path = "../tree" } diff --git a/software/tree/native/crates/cmd-tree/src/main.rs b/software/tree/native/crates/cmd-tree/src/main.rs deleted file mode 100644 index ee799a4287..0000000000 --- a/software/tree/native/crates/cmd-tree/src/main.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let args: Vec = std::env::args_os().collect(); - std::process::exit(secureexec_tree::main(args)); -} diff --git a/software/tree/native/crates/tree/Cargo.toml b/software/tree/native/crates/tree/Cargo.toml deleted file mode 100644 index e316d0fda4..0000000000 --- a/software/tree/native/crates/tree/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -workspace = "../../../../../toolchain" -name = "secureexec-tree" -version.workspace = true -edition.workspace = true -license.workspace = true -description = "tree implementation for secure-exec standalone binaries" - -[dependencies] diff --git a/software/tree/native/crates/tree/src/lib.rs b/software/tree/native/crates/tree/src/lib.rs deleted file mode 100644 index 71cfb7044c..0000000000 --- a/software/tree/native/crates/tree/src/lib.rs +++ /dev/null @@ -1,268 +0,0 @@ -//! tree -- list directory contents in a tree-like format -//! -//! Recursive directory walk with box-drawing characters. -//! Supports -a (show hidden), -d (dirs only), -L depth, -I exclude pattern. - -use std::ffi::OsString; -use std::fs; -use std::io::{self, Write}; -use std::path::Path; - -const DEFAULT_MAX_DEPTH: usize = 256; -const MAX_TOTAL_ENTRIES: usize = 100_000; -const MAX_DIRECTORY_ENTRIES: usize = 100_000; - -pub fn main(args: Vec) -> i32 { - let str_args: Vec = args - .iter() - .skip(1) - .map(|a| a.to_string_lossy().to_string()) - .collect(); - - let mut show_hidden = false; - let mut dirs_only = false; - let mut max_depth: Option = None; - let mut exclude_pattern: Option = None; - let mut paths: Vec = Vec::new(); - - let mut i = 0; - while i < str_args.len() { - match str_args[i].as_str() { - "-a" => show_hidden = true, - "-d" => dirs_only = true, - "-L" => { - i += 1; - if i >= str_args.len() { - eprintln!("tree: option '-L' requires an argument"); - return 1; - } - match str_args[i].parse::() { - Ok(d) => max_depth = Some(d), - Err(_) => { - eprintln!("tree: invalid level '{}'", str_args[i]); - return 1; - } - } - } - "-I" => { - i += 1; - if i >= str_args.len() { - eprintln!("tree: option '-I' requires an argument"); - return 1; - } - exclude_pattern = Some(str_args[i].clone()); - } - s if s.starts_with('-') => { - eprintln!("tree: unknown option '{}'", s); - return 1; - } - _ => paths.push(str_args[i].clone()), - } - i += 1; - } - - if paths.is_empty() { - paths.push(".".to_string()); - } - - let stdout = io::stdout(); - let mut out = stdout.lock(); - let mut dir_count: usize = 0; - let mut file_count: usize = 0; - - for (idx, path) in paths.iter().enumerate() { - if let Err(e) = writeln!(out, "{}", path).and_then(|_| { - walk_tree( - Path::new(path), - "", - 1, - max_depth, - show_hidden, - dirs_only, - exclude_pattern.as_deref(), - &mut dir_count, - &mut file_count, - &mut out, - ) - }) { - eprintln!("tree: {}", e); - return 1; - } - if idx + 1 < paths.len() { - if let Err(e) = writeln!(out) { - eprintln!("tree: {}", e); - return 1; - } - } - } - - if let Err(e) = writeln!(out) { - eprintln!("tree: {}", e); - return 1; - } - if dirs_only { - if let Err(e) = writeln!( - out, - "{} director{}", - dir_count, - if dir_count == 1 { "y" } else { "ies" } - ) { - eprintln!("tree: {}", e); - return 1; - } - } else { - if let Err(e) = writeln!( - out, - "{} director{}, {} file{}", - dir_count, - if dir_count == 1 { "y" } else { "ies" }, - file_count, - if file_count == 1 { "" } else { "s" } - ) { - eprintln!("tree: {}", e); - return 1; - } - } - - match out.flush() { - Ok(()) => 0, - Err(e) => { - eprintln!("tree: {}", e); - 1 - } - } -} - -fn matches_exclude(name: &str, pattern: &str) -> bool { - // Simple glob matching: supports * as wildcard - if pattern.contains('*') { - let parts: Vec<&str> = pattern.split('*').collect(); - if parts.len() == 2 { - let (prefix, suffix) = (parts[0], parts[1]); - return name.starts_with(prefix) && name.ends_with(suffix); - } - // Fallback: check if any non-wildcard part matches - parts.iter().all(|p| p.is_empty() || name.contains(p)) - } else { - name == pattern - } -} - -fn walk_tree( - dir: &Path, - prefix: &str, - depth: usize, - max_depth: Option, - show_hidden: bool, - dirs_only: bool, - exclude: Option<&str>, - dir_count: &mut usize, - file_count: &mut usize, - out: &mut W, -) -> io::Result<()> { - if let Some(max) = max_depth { - if depth > max { - return Ok(()); - } - } else if depth > DEFAULT_MAX_DEPTH { - return Ok(()); - } - - let mut entries: Vec = match fs::read_dir(dir) { - Ok(rd) => { - let mut entries = Vec::new(); - for entry_result in rd { - let entry = entry_result?; - if entries.len() >= MAX_DIRECTORY_ENTRIES { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("too many entries in {}", dir.display()), - )); - } - entries.push(entry); - } - entries - } - Err(e) => { - writeln!(out, "{}[error opening dir: {}]", prefix, e)?; - return Ok(()); - } - }; - - // Sort entries alphabetically - entries.sort_by(|a, b| a.file_name().cmp(&b.file_name())); - - // Filter entries - entries.retain(|e| { - let name = e.file_name().to_string_lossy().to_string(); - // Skip hidden unless -a - if !show_hidden && name.starts_with('.') { - return false; - } - // Skip excluded patterns - if let Some(pat) = exclude { - if matches_exclude(&name, pat) { - return false; - } - } - // Skip files if -d - if dirs_only { - if let Ok(ft) = e.file_type() { - if !ft.is_dir() { - return false; - } - } - } - true - }); - - let count = entries.len(); - - for (idx, entry) in entries.iter().enumerate() { - if *dir_count + *file_count >= MAX_TOTAL_ENTRIES { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "too many tree entries", - )); - } - - let is_last = idx + 1 == count; - let connector = if is_last { - "\u{2514}\u{2500}\u{2500} " // └── - } else { - "\u{251c}\u{2500}\u{2500} " // ├── - }; - - let name = entry.file_name().to_string_lossy().to_string(); - let file_type = entry.file_type()?; - let is_dir = file_type.is_dir() && !file_type.is_symlink(); - - write!(out, "{}{}", prefix, connector)?; - writeln!(out, "{}", name)?; - - if is_dir { - *dir_count += 1; - let child_prefix = if is_last { - format!("{} ", prefix) - } else { - format!("{}\u{2502} ", prefix) // │ - }; - walk_tree( - &dir.join(&name), - &child_prefix, - depth + 1, - max_depth, - show_hidden, - dirs_only, - exclude, - dir_count, - file_count, - out, - )?; - } else { - *file_count += 1; - } - } - - Ok(()) -} diff --git a/software/tree/package.json b/software/tree/package.json index bca79a144c..45d2aee6d2 100644 --- a/software/tree/package.json +++ b/software/tree/package.json @@ -2,7 +2,7 @@ "name": "@agentos-software/tree", "version": "0.3.3", "type": "module", - "license": "Apache-2.0", + "license": "GPL-2.0-or-later", "description": "tree directory listing for secure-exec VMs", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/software/tree/test/tree-test.test.ts b/software/tree/test/tree-test.test.ts index 4ad659d78f..0c505f5ff0 100644 --- a/software/tree/test/tree-test.test.ts +++ b/software/tree/test/tree-test.test.ts @@ -65,8 +65,8 @@ describeIf(!wasmSkip, 'tree command behavior', () => { expect(result.stdout).toContain('types.ts'); expect(result.stdout).toContain('index.ts'); expect(result.stdout).toContain('README.md'); - // Should show 2 directories (src, lib) and 4 files - expect(result.stdout).toMatch(/2 director/); + // Upstream tree reports the displayed root plus src/lib. + expect(result.stdout).toMatch(/3 director/); expect(result.stdout).toMatch(/4 file/); }, TREE_TEST_TIMEOUT_MS); diff --git a/toolchain/Cargo.lock b/toolchain/Cargo.lock index 5356b72d22..0c8cfd808d 100644 --- a/toolchain/Cargo.lock +++ b/toolchain/Cargo.lock @@ -1352,13 +1352,6 @@ dependencies = [ "uu_tr", ] -[[package]] -name = "cmd-tree" -version = "0.1.0" -dependencies = [ - "secureexec-tree", -] - [[package]] name = "cmd-true" version = "0.1.0" @@ -4030,10 +4023,6 @@ dependencies = [ "tar", ] -[[package]] -name = "secureexec-tree" -version = "0.1.0" - [[package]] name = "secureexec-wasi-http" version = "0.1.0" diff --git a/toolchain/c/Makefile b/toolchain/c/Makefile index 484e923abc..1d23d461e2 100644 --- a/toolchain/c/Makefile +++ b/toolchain/c/Makefile @@ -68,10 +68,10 @@ COMMANDS_DIR ?= ../target/wasm32-wasip1/release/commands # Fast real commands installed by the default software gate. Slow/heavy commands # (duckdb, vim) remain available through explicit parent `make cmd/`. -COMMANDS := zip unzip envsubst sqlite3 curl wget http_get +COMMANDS := zip unzip envsubst sqlite3 curl wget tree http_get # Programs requiring patched sysroot (Tier 2+ custom host imports) -PATCHED_PROGRAMS := http_get_test isatty_test getpid_test getppid_test getppid_verify userinfo pipe_test dup_test spawn_child spawn_exit_code pipeline kill_child waitpid_return waitpid_edge syscall_coverage getpwuid_test signal_tests sigaction_self sigaction_behavior delayed_tcp_echo delayed_kill pipe_edge tcp_accept_spawn tcp_echo tcp_server http_server udp_echo unix_socket signal_handler http_get dns_lookup sqlite3 curl wget fs_probe +PATCHED_PROGRAMS := http_get_test isatty_test getpid_test getppid_test getppid_verify userinfo pipe_test dup_test spawn_child spawn_exit_code pipeline kill_child waitpid_return waitpid_edge syscall_coverage getpwuid_test signal_tests sigaction_self sigaction_behavior delayed_tcp_echo delayed_kill pipe_edge tcp_accept_spawn tcp_echo tcp_server http_server udp_echo unix_socket signal_handler http_get dns_lookup sqlite3 curl wget tree fs_probe # Discover all package command and test-program C source files. ALL_SOURCES := $(foreach dir,$(C_SOURCE_DIRS),$(wildcard $(dir)/*.c)) @@ -89,7 +89,7 @@ endif ifeq ($(wildcard $(PATCHED_SYSROOT)/lib/wasm32-wasi/libc.a),) CUSTOM_WASM_PROG_NAMES := else - CUSTOM_WASM_PROG_NAMES := curl wget sqlite3 + CUSTOM_WASM_PROG_NAMES := curl wget sqlite3 tree endif WASM_PROG_NAMES := $(sort $(basename $(notdir $(SOURCES))) $(CUSTOM_WASM_PROG_NAMES)) @@ -156,6 +156,8 @@ WGET_URL := https://ftp.gnu.org/gnu/wget/wget-$(WGET_VERSION).tar.gz WGET_UPSTREAM_BUILD_DIR := $(BUILD_DIR)/wget-upstream WGET_UPSTREAM_OVERLAY_INCLUDE_DIR := overlays/wget/include WGET_UPSTREAM_OVERLAY_FILES := $(wildcard $(WGET_UPSTREAM_OVERLAY_INCLUDE_DIR)/*.h) +TREE_VERSION := 2.3.2 +TREE_URL := https://gitlab.com/OldManProgrammer/unix-tree/-/archive/$(TREE_VERSION)/unix-tree-$(TREE_VERSION).tar.gz MINIZIP_URL := https://github.com/madler/zlib/archive/refs/tags/v1.3.1.zip # duckdb-wasm currently documents DuckDB v1.5.0 in its README. We build the # matching upstream DuckDB tag ourselves with our patched WASI/POSIX sysroot. @@ -166,6 +168,10 @@ DUCKDB_URL := https://github.com/duckdb/duckdb/archive/refs/tags/$(DUCKDB_VERSIO LIBS_DIR := libs LIBS_CACHE := .cache/libs +TREE_SOURCES := color.c file.c filter.c hash.c html.c info.c json.c list.c tree.c unix.c util.c xml.c strverscmp.c +TREE_FILES := $(addprefix $(LIBS_DIR)/tree/,$(TREE_SOURCES) tree.h) +TREE_WASM_FLAGS := -DLARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 + libs/sqlite3/sqlite3.c libs/sqlite3/sqlite3.h libs/sqlite3/shell.c: @echo "Fetching sqlite3..." @mkdir -p $(LIBS_CACHE) $(LIBS_DIR)/sqlite3 @@ -176,6 +182,17 @@ libs/sqlite3/sqlite3.c libs/sqlite3/sqlite3.h libs/sqlite3/shell.c: $(LIBS_CACHE)/sqlite-amalgamation-*/shell.c \ $(LIBS_DIR)/sqlite3/ +$(TREE_FILES): $(LIBS_DIR)/tree/.fetched + +$(LIBS_DIR)/tree/.fetched: + @echo "Fetching upstream tree $(TREE_VERSION)..." + @mkdir -p $(LIBS_CACHE) $(LIBS_DIR)/tree + @curl -fSL "$(TREE_URL)" -o "$(LIBS_CACHE)/tree-$(TREE_VERSION).tar.gz" + @rm -rf "$(LIBS_CACHE)/unix-tree-$(TREE_VERSION)" + @tar -xzf "$(LIBS_CACHE)/tree-$(TREE_VERSION).tar.gz" -C "$(LIBS_CACHE)" + @cp $(addprefix $(LIBS_CACHE)/unix-tree-$(TREE_VERSION)/,$(TREE_SOURCES) tree.h) $(LIBS_DIR)/tree/ + @touch $@ + libs/zlib/zutil.c: @echo "Fetching zlib..." @mkdir -p $(LIBS_CACHE) $(LIBS_DIR)/zlib @@ -520,6 +537,18 @@ $(NATIVE_DIR)/sqlite3: libs/sqlite3/shell.c libs/sqlite3/sqlite3.c $(NATIVE_DIR)/sqlite3_cli: $(NATIVE_DIR)/sqlite3 cp $< $@ +# tree: upstream Steve Baker tree compiled from pinned C source. +$(BUILD_DIR)/tree: $(TREE_FILES) $(WASI_SDK_DIR)/bin/clang $(PATCHED_SYSROOT)/lib/wasm32-wasi/libc.a + @mkdir -p $(BUILD_DIR) + $(CC) --target=wasm32-wasip1 --sysroot=$(SYSROOT) -O2 -I include/ \ + $(TREE_WASM_FLAGS) -I$(LIBS_DIR)/tree -o $@ \ + $(addprefix $(LIBS_DIR)/tree/,$(TREE_SOURCES)) + +$(NATIVE_DIR)/tree: $(TREE_FILES) + @mkdir -p $(NATIVE_DIR) + $(NATIVE_CC) $(NATIVE_CFLAGS) $(TREE_WASM_FLAGS) -I$(LIBS_DIR)/tree -o $@ \ + $(addprefix $(LIBS_DIR)/tree/,$(TREE_SOURCES)) + # zip: links zlib + minizip ZLIB_SRCS := libs/zlib/adler32.c libs/zlib/compress.c libs/zlib/crc32.c libs/zlib/deflate.c \ libs/zlib/infback.c libs/zlib/inffast.c libs/zlib/inflate.c libs/zlib/inftrees.c \ diff --git a/toolchain/std-patches/wasi-libc/0024-install-group-header.patch b/toolchain/std-patches/wasi-libc/0024-install-group-header.patch new file mode 100644 index 0000000000..89f6e834d8 --- /dev/null +++ b/toolchain/std-patches/wasi-libc/0024-install-group-header.patch @@ -0,0 +1,22 @@ +Install POSIX group lookup declarations in the AgentOS WASI sysroot. + +Upstream tools such as tree include for optional group-name display. +The patched sysroot already carries musl's group lookup implementation and +AgentOS exposes deterministic gid/getgroups behavior, so the header should be +installed instead of forcing application-level WASI branches. + +diff --git a/scripts/install-include-headers.sh b/scripts/install-include-headers.sh +index 4a9f079..d589a77 100755 +--- a/scripts/install-include-headers.sh ++++ b/scripts/install-include-headers.sh +@@ -62,7 +62,7 @@ MUSL_OMIT_HEADERS+=("sys/procfs.h" "sys/user.h" "sys/kd.h" "sys/vt.h" \ + "sys/swap.h" "sys/sendfile.h" "sys/inotify.h" "sys/quota.h" "sys/klog.h" \ + "sys/fsuid.h" "sys/io.h" "sys/prctl.h" "sys/mtio.h" "sys/mount.h" \ + "sys/fanotify.h" "sys/personality.h" "elf.h" "link.h" "bits/link.h" \ +- "scsi/scsi.h" "scsi/scsi_ioctl.h" "scsi/sg.h" "sys/auxv.h" \ +- "shadow.h" "grp.h" "mntent.h" "resolv.h" "pty.h" "ulimit.h" "sys/xattr.h" \ ++ "scsi/scsi.h" "scsi/scsi_ioctl.h" "scsi/sg.h" "sys/auxv.h" \ ++ "shadow.h" "mntent.h" "resolv.h" "pty.h" "ulimit.h" "sys/xattr.h" \ + "wordexp.h" "sys/membarrier.h" "sys/signalfd.h" \ + "net/if.h" "net/if_arp.h" \ + "net/ethernet.h" "net/route.h" "netinet/if_ether.h" "netinet/ether.h" \ diff --git a/toolchain/std-patches/wasi-libc/0025-group-lookup-compat.patch b/toolchain/std-patches/wasi-libc/0025-group-lookup-compat.patch new file mode 100644 index 0000000000..febdbaf4bf --- /dev/null +++ b/toolchain/std-patches/wasi-libc/0025-group-lookup-compat.patch @@ -0,0 +1,58 @@ +Provide group lookup compatibility entry points in AgentOS wasi-libc. + +Tree links getgrgid() for optional `-g` group-name output. AgentOS VMs expose +numeric gid/getgroups behavior but do not project a group database, so group +name lookups should fail deterministically and let callers fall back to numeric +gids. + +diff --git a/libc-bottom-half/sources/host_resource_user.c b/libc-bottom-half/sources/host_resource_user.c +index 8d91a2f..aa78a47 100644 +--- a/libc-bottom-half/sources/host_resource_user.c ++++ b/libc-bottom-half/sources/host_resource_user.c +@@ -2,6 +2,8 @@ + + #include ++#include ++#include + #include + #include + #include + #include +@@ -48,5 +50,37 @@ int getgroups(int size, gid_t list[]) { + list[0] = getgid(); + return 1; + } + ++struct group *getgrgid(gid_t gid) { ++ (void)gid; ++ errno = ENOENT; ++ return NULL; ++} ++ ++struct group *getgrnam(const char *name) { ++ (void)name; ++ errno = ENOENT; ++ return NULL; ++} ++ ++int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen, ++ struct group **result) { ++ (void)gid; ++ (void)grp; ++ (void)buf; ++ (void)buflen; ++ *result = NULL; ++ return ENOENT; ++} ++ ++int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, ++ struct group **result) { ++ (void)name; ++ (void)grp; ++ (void)buf; ++ (void)buflen; ++ *result = NULL; ++ return ENOENT; ++} ++ + int getrlimit(int resource, struct rlimit *rlim) {