@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
461 lines • 17.6 kB
JavaScript
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import { PathSpec } from "../../../types.js";
import { IOResult } from "../../../io/types.js";
import { command } from "../../config.js";
import { specOf } from "../../spec/builtins.js";
import { FlagView } from "../../spec/flag_view.js";
import { vfsStatPath } from "../utils/paths.js";
const ENC = new TextEncoder();
const USAGE = 'Usage: getconf [-v specification] variable_name [pathname]\n' + ' getconf -a [pathname]\n';
const UNDEFINED = 'undefined';
// The table `getconf -a` prints, in Mirage's order: POSIX.1-2024's
// tables first, then earlier standards, then Linux's names. null is
// undefined; a confstr() name that is set but empty is ''.
const GETCONF_VARIABLES = [
// The pathname variables, in the order of the fpathconf() table in
// POSIX.1-2024, as Linux answers them for a filesystem it has no entry for:
// the terminal and link limits from <linux/limits.h>, a 4096-byte page for
// the transfer sizes, 32 FILESIZEBITS.
['FILESIZEBITS', '32'],
['LINK_MAX', '127'],
['MAX_CANON', '255'],
['MAX_INPUT', '255'],
['NAME_MAX', '255'],
['PATH_MAX', '4096'],
['PIPE_BUF', '4096'],
['POSIX2_SYMLINKS', '1'],
['POSIX_ALLOC_SIZE_MIN', '4096'],
['POSIX_REC_INCR_XFER_SIZE', null],
['POSIX_REC_MAX_XFER_SIZE', null],
['POSIX_REC_MIN_XFER_SIZE', '4096'],
['POSIX_REC_XFER_ALIGN', '4096'],
['SYMLINK_MAX', null],
['_POSIX_CHOWN_RESTRICTED', '1'],
['_POSIX_NO_TRUNC', '1'],
['_POSIX_VDISABLE', '0'],
['_POSIX_ASYNC_IO', null],
['_POSIX_PRIO_IO', null],
['_POSIX_SYNC_IO', null],
// Local pathname names: the _POSIX_ name of a pathname limit answers
// the limit itself, as the image's getconf does, not POSIX's minimum.
['_POSIX_LINK_MAX', '127'],
['_POSIX_MAX_CANON', '255'],
['_POSIX_MAX_INPUT', '255'],
['_POSIX_NAME_MAX', '255'],
['_POSIX_PATH_MAX', '4096'],
['_POSIX_PIPE_BUF', '4096'],
['SOCK_MAXBUF', null],
// The sysconf() variables, in the order of its table in POSIX.1-2024,
// for x86_64 Linux in a container: ARG_MAX is a quarter of the 8 MiB stack
// limit, CLK_TCK is USER_HZ, OPEN_MAX the soft RLIMIT_NOFILE and CHILD_MAX
// an unlimited RLIMIT_NPROC; the options carry POSIX.1-2008's 200809 and
// the X/Open ones SUSv4's 700. One execution unit and no signal queue
// limit, as host detail stays out.
['AIO_LISTIO_MAX', null],
['AIO_MAX', null],
['AIO_PRIO_DELTA_MAX', '20'],
['ARG_MAX', '2097152'],
['ATEXIT_MAX', '2147483647'],
['BC_BASE_MAX', '99'],
['BC_DIM_MAX', '2048'],
['BC_SCALE_MAX', '99'],
['BC_STRING_MAX', '1000'],
['CHILD_MAX', null],
['CLK_TCK', '100'],
['COLL_WEIGHTS_MAX', '255'],
['DELAYTIMER_MAX', '2147483647'],
['EXPR_NEST_MAX', '32'],
['HOST_NAME_MAX', '64'],
['IOV_MAX', '1024'],
['LINE_MAX', '2048'],
['LOGIN_NAME_MAX', '256'],
['NGROUPS_MAX', '65536'],
['MQ_OPEN_MAX', null],
['MQ_PRIO_MAX', '32768'],
['OPEN_MAX', '1048576'],
['PAGE_SIZE', '4096'],
['PAGESIZE', '4096'],
['PTHREAD_DESTRUCTOR_ITERATIONS', '4'],
['PTHREAD_KEYS_MAX', '1024'],
['PTHREAD_STACK_MIN', '16384'],
['PTHREAD_THREADS_MAX', null],
['RE_DUP_MAX', '32767'],
['RTSIG_MAX', '32'],
['SEM_NSEMS_MAX', null],
['SEM_VALUE_MAX', '2147483647'],
['SIGQUEUE_MAX', null],
['STREAM_MAX', '16'],
['SYMLOOP_MAX', null],
['TIMER_MAX', null],
['TTY_NAME_MAX', '32'],
['TZNAME_MAX', null],
['_POSIX_ADVISORY_INFO', '200809'],
['_POSIX_BARRIERS', '200809'],
['_POSIX_ASYNCHRONOUS_IO', '200809'],
['_POSIX_CLOCK_SELECTION', '200809'],
['_POSIX_CPUTIME', '200809'],
['_POSIX_FSYNC', '200809'],
['_POSIX_IPV6', '200809'],
['_POSIX_JOB_CONTROL', '1'],
['_POSIX_MAPPED_FILES', '200809'],
['_POSIX_MEMLOCK', '200809'],
['_POSIX_MEMLOCK_RANGE', '200809'],
['_POSIX_MEMORY_PROTECTION', '200809'],
['_POSIX_MESSAGE_PASSING', '200809'],
['_POSIX_MONOTONIC_CLOCK', '200809'],
['_POSIX_PRIORITIZED_IO', '200809'],
['_POSIX_PRIORITY_SCHEDULING', '200809'],
['_POSIX_RAW_SOCKETS', '200809'],
['_POSIX_READER_WRITER_LOCKS', '200809'],
['_POSIX_REALTIME_SIGNALS', '200809'],
['_POSIX_REGEXP', '1'],
['_POSIX_SAVED_IDS', '1'],
['_POSIX_SEMAPHORES', '200809'],
['_POSIX_SHARED_MEMORY_OBJECTS', '200809'],
['_POSIX_SHELL', '1'],
['_POSIX_SPAWN', '200809'],
['_POSIX_SPIN_LOCKS', '200809'],
['_POSIX_SPORADIC_SERVER', null],
['_POSIX_SYNCHRONIZED_IO', '200809'],
['_POSIX_THREAD_ATTR_STACKADDR', '200809'],
['_POSIX_THREAD_ATTR_STACKSIZE', '200809'],
['_POSIX_THREAD_CPUTIME', '200809'],
['_POSIX_THREAD_PRIO_INHERIT', '200809'],
['_POSIX_THREAD_PRIO_PROTECT', '200809'],
['_POSIX_THREAD_PRIORITY_SCHEDULING', '200809'],
['_POSIX_THREAD_PROCESS_SHARED', '200809'],
['_POSIX_THREAD_ROBUST_PRIO_INHERIT', null],
['_POSIX_THREAD_ROBUST_PRIO_PROTECT', null],
['_POSIX_THREAD_SAFE_FUNCTIONS', '200809'],
['_POSIX_THREAD_SPORADIC_SERVER', null],
['_POSIX_THREADS', '200809'],
['_POSIX_TIMEOUTS', '200809'],
['_POSIX_TIMERS', '200809'],
['_POSIX_TYPED_MEMORY_OBJECTS', null],
['_POSIX_VERSION', '200809'],
['_POSIX_V7_ILP32_OFF32', null],
['_POSIX_V7_ILP32_OFFBIG', null],
['_POSIX_V7_LP64_OFF64', '1'],
['_POSIX_V7_LPBIG_OFFBIG', null],
['_XOPEN_CRYPT', null],
['_XOPEN_ENH_I18N', '1'],
['_XOPEN_REALTIME', '1'],
['_XOPEN_REALTIME_THREADS', '1'],
['_XOPEN_SHM', '1'],
['_XOPEN_UNIX', '1'],
['_XOPEN_VERSION', '700'],
['NPROCESSORS_CONF', '1'],
['NPROCESSORS_ONLN', '1'],
// The names POSIX.1-2024's getconf keeps for compatibility, each equal
// to the same name with a leading underscore.
['POSIX2_C_BIND', '200809'],
['POSIX2_C_DEV', '200809'],
['POSIX2_CHAR_TERM', '200809'],
['POSIX2_FORT_RUN', null],
['POSIX2_LOCALEDEF', '200809'],
['POSIX2_SW_DEV', '200809'],
['POSIX2_UPE', null],
['POSIX2_VERSION', '200809'],
['POSIX2_BC_BASE_MAX', '99'],
['POSIX2_BC_DIM_MAX', '2048'],
['POSIX2_BC_SCALE_MAX', '99'],
['POSIX2_BC_STRING_MAX', '1000'],
['POSIX2_COLL_WEIGHTS_MAX', '255'],
['POSIX2_EXPR_NEST_MAX', '32'],
['POSIX2_LINE_MAX', '2048'],
['POSIX2_RE_DUP_MAX', '32767'],
// The confstr() names, in the order of its table in POSIX.1-2024, for
// LP64 x86_64, whose one native environment is LP64_OFF64.
['PATH', '/bin:/usr/bin'],
['POSIX_V7_ILP32_OFF32_CFLAGS', ''],
['POSIX_V7_ILP32_OFF32_LDFLAGS', ''],
['POSIX_V7_ILP32_OFF32_LIBS', ''],
['POSIX_V7_ILP32_OFFBIG_CFLAGS', ''],
['POSIX_V7_ILP32_OFFBIG_LDFLAGS', ''],
['POSIX_V7_ILP32_OFFBIG_LIBS', ''],
['POSIX_V7_LP64_OFF64_CFLAGS', '-m64'],
['POSIX_V7_LP64_OFF64_LDFLAGS', '-m64'],
['POSIX_V7_LP64_OFF64_LIBS', ''],
['POSIX_V7_LPBIG_OFFBIG_CFLAGS', ''],
['POSIX_V7_LPBIG_OFFBIG_LDFLAGS', ''],
['POSIX_V7_LPBIG_OFFBIG_LIBS', ''],
['POSIX_V7_WIDTH_RESTRICTED_ENVS', 'POSIX_V7_LP64_OFF64'],
// <limits.h>: Runtime Increasable, Minimum, Numerical and Other
// Invariant Values, for LP64 x86_64 (char is signed). A _POSIX_ minimum
// answers the runtime value, but _POSIX_SSIZE_MAX answers POSIX's 32767,
// and SSIZE_MAX answers that minimum too, as the image's getconf does.
['CHARCLASS_NAME_MAX', '2048'],
['_POSIX_ARG_MAX', '2097152'],
['_POSIX_CHILD_MAX', null],
['_POSIX_NGROUPS_MAX', '65536'],
['_POSIX_OPEN_MAX', '1048576'],
['_POSIX_SSIZE_MAX', '32767'],
['_POSIX_STREAM_MAX', '16'],
['_POSIX_TZNAME_MAX', null],
['_POSIX2_LINE_MAX', '2048'],
['CHAR_BIT', '8'],
['CHAR_MAX', '127'],
['CHAR_MIN', '-128'],
['INT_MAX', '2147483647'],
['INT_MIN', '-2147483648'],
['LONG_BIT', '64'],
['MB_LEN_MAX', '16'],
['SCHAR_MAX', '127'],
['SCHAR_MIN', '-128'],
['SHRT_MAX', '32767'],
['SHRT_MIN', '-32768'],
['SSIZE_MAX', '32767'],
['UCHAR_MAX', '255'],
['UINT_MAX', '4294967295'],
['ULONG_MAX', '18446744073709551615'],
['USHRT_MAX', '65535'],
['WORD_BIT', '32'],
['NL_ARGMAX', '4096'],
['NL_LANGMAX', '2048'],
['NL_MSGMAX', '2147483647'],
['NL_SETMAX', '2147483647'],
['NL_TEXTMAX', '2147483647'],
['NZERO', '20'],
// Names from earlier standards Linux still answers: Issue 6's
// compilation environments and LINTFLAGS, SUSv2's XBS5 environments, the
// Large File Summit's flags, Issue 6's batch and trace options, XPG's
// version names and IEEE 1003.1g's and 1003.13's options.
['POSIX_V7_ILP32_OFF32_LINTFLAGS', ''],
['POSIX_V7_ILP32_OFFBIG_LINTFLAGS', ''],
['POSIX_V7_LP64_OFF64_LINTFLAGS', ''],
['POSIX_V7_LPBIG_OFFBIG_LINTFLAGS', ''],
['_POSIX_V7_WIDTH_RESTRICTED_ENVS', 'POSIX_V7_LP64_OFF64'],
['_POSIX_V6_ILP32_OFF32', null],
['_POSIX_V6_ILP32_OFFBIG', null],
['_POSIX_V6_LP64_OFF64', '1'],
['_POSIX_V6_LPBIG_OFFBIG', null],
['POSIX_V6_ILP32_OFF32_CFLAGS', ''],
['POSIX_V6_ILP32_OFF32_LDFLAGS', ''],
['POSIX_V6_ILP32_OFF32_LIBS', ''],
['POSIX_V6_ILP32_OFF32_LINTFLAGS', ''],
['POSIX_V6_ILP32_OFFBIG_CFLAGS', ''],
['POSIX_V6_ILP32_OFFBIG_LDFLAGS', ''],
['POSIX_V6_ILP32_OFFBIG_LIBS', ''],
['POSIX_V6_ILP32_OFFBIG_LINTFLAGS', ''],
['POSIX_V6_LP64_OFF64_CFLAGS', '-m64'],
['POSIX_V6_LP64_OFF64_LDFLAGS', '-m64'],
['POSIX_V6_LP64_OFF64_LIBS', ''],
['POSIX_V6_LP64_OFF64_LINTFLAGS', ''],
['POSIX_V6_LPBIG_OFFBIG_CFLAGS', ''],
['POSIX_V6_LPBIG_OFFBIG_LDFLAGS', ''],
['POSIX_V6_LPBIG_OFFBIG_LIBS', ''],
['POSIX_V6_LPBIG_OFFBIG_LINTFLAGS', ''],
['_POSIX_V6_WIDTH_RESTRICTED_ENVS', 'POSIX_V6_LP64_OFF64'],
['POSIX_V6_WIDTH_RESTRICTED_ENVS', 'POSIX_V6_LP64_OFF64'],
['_XBS5_ILP32_OFF32', null],
['_XBS5_ILP32_OFFBIG', null],
['_XBS5_LP64_OFF64', '1'],
['_XBS5_LPBIG_OFFBIG', null],
['XBS5_ILP32_OFF32_CFLAGS', ''],
['XBS5_ILP32_OFF32_LDFLAGS', ''],
['XBS5_ILP32_OFF32_LIBS', ''],
['XBS5_ILP32_OFF32_LINTFLAGS', ''],
['XBS5_ILP32_OFFBIG_CFLAGS', ''],
['XBS5_ILP32_OFFBIG_LDFLAGS', ''],
['XBS5_ILP32_OFFBIG_LIBS', ''],
['XBS5_ILP32_OFFBIG_LINTFLAGS', ''],
['XBS5_LP64_OFF64_CFLAGS', '-m64'],
['XBS5_LP64_OFF64_LDFLAGS', '-m64'],
['XBS5_LP64_OFF64_LIBS', ''],
['XBS5_LP64_OFF64_LINTFLAGS', ''],
['XBS5_LPBIG_OFFBIG_CFLAGS', ''],
['XBS5_LPBIG_OFFBIG_LDFLAGS', ''],
['XBS5_LPBIG_OFFBIG_LIBS', ''],
['XBS5_LPBIG_OFFBIG_LINTFLAGS', ''],
['_XBS5_WIDTH_RESTRICTED_ENVS', 'XBS5_LP64_OFF64'],
['XBS5_WIDTH_RESTRICTED_ENVS', 'XBS5_LP64_OFF64'],
['LFS_CFLAGS', ''],
['LFS_LDFLAGS', ''],
['LFS_LIBS', ''],
['LFS_LINTFLAGS', ''],
['LFS64_CFLAGS', '-D_LARGEFILE64_SOURCE'],
['LFS64_LDFLAGS', ''],
['LFS64_LIBS', ''],
['LFS64_LINTFLAGS', '-D_LARGEFILE64_SOURCE'],
['POSIX2_C_VERSION', '200809'],
['POSIX2_FORT_DEV', null],
['POSIX2_PBS', null],
['POSIX2_PBS_ACCOUNTING', null],
['POSIX2_PBS_LOCATE', null],
['POSIX2_PBS_MESSAGE', null],
['POSIX2_PBS_TRACK', null],
['_POSIX_TRACE', null],
['_POSIX_TRACE_EVENT_FILTER', null],
['_POSIX_TRACE_INHERIT', null],
['_POSIX_TRACE_LOG', null],
['_XOPEN_LEGACY', '1'],
['_XOPEN_XCU_VERSION', '4'],
['_XOPEN_XPG2', '1'],
['_XOPEN_XPG3', '1'],
['_XOPEN_XPG4', '1'],
['NL_NMAX', '2147483647'],
['EQUIV_CLASS_MAX', null],
['_T_IOV_MAX', null],
['_POSIX_PII', null],
['_POSIX_PII_INTERNET', null],
['_POSIX_PII_INTERNET_DGRAM', null],
['_POSIX_PII_INTERNET_STREAM', null],
['_POSIX_PII_OSI', null],
['_POSIX_PII_OSI_CLTS', null],
['_POSIX_PII_OSI_COTS', null],
['_POSIX_PII_OSI_M', null],
['_POSIX_PII_SOCKET', null],
['_POSIX_PII_XTI', null],
['_POSIX_POLL', null],
['_POSIX_SELECT', null],
['_POSIX_BASE', null],
['_POSIX_C_LANG_SUPPORT', null],
['_POSIX_C_LANG_SUPPORT_R', null],
['_POSIX_DEVICE_IO', null],
['_POSIX_DEVICE_SPECIFIC', null],
['_POSIX_DEVICE_SPECIFIC_R', null],
['_POSIX_FD_MGMT', null],
['_POSIX_FIFO', null],
['_POSIX_FILE_ATTRIBUTES', null],
['_POSIX_FILE_LOCKING', null],
['_POSIX_FILE_SYSTEM', null],
['_POSIX_MULTI_PROCESS', null],
['_POSIX_NETWORKING', null],
['_POSIX_PIPE', null],
['_POSIX_SIGNALS', null],
['_POSIX_SINGLE_PROCESS', null],
['_POSIX_SYSTEM_DATABASE', null],
['_POSIX_SYSTEM_DATABASE_R', null],
['_POSIX_USER_GROUPS', null],
['_POSIX_USER_GROUPS_R', null],
['_REGEX_VERSION', null],
// Linux's own names (sysconf(3) and confstr(3) in the man-pages), and
// the C library version the image reports. Host detail stays out, as
// uname's does: no memory or cache figures.
['_NPROCESSORS_CONF', '1'],
['_NPROCESSORS_ONLN', '1'],
['_PHYS_PAGES', null],
['_AVPHYS_PAGES', null],
['LEVEL1_ICACHE_SIZE', null],
['LEVEL1_ICACHE_ASSOC', null],
['LEVEL1_ICACHE_LINESIZE', null],
['LEVEL1_DCACHE_SIZE', null],
['LEVEL1_DCACHE_ASSOC', null],
['LEVEL1_DCACHE_LINESIZE', null],
['LEVEL2_CACHE_SIZE', null],
['LEVEL2_CACHE_ASSOC', null],
['LEVEL2_CACHE_LINESIZE', null],
['LEVEL3_CACHE_SIZE', null],
['LEVEL3_CACHE_ASSOC', null],
['LEVEL3_CACHE_LINESIZE', null],
['LEVEL4_CACHE_SIZE', null],
['LEVEL4_CACHE_ASSOC', null],
['LEVEL4_CACHE_LINESIZE', null],
['IPV6', '200809'],
['RAW_SOCKETS', '200809'],
['CS_PATH', '/bin:/usr/bin'],
['GNU_LIBC_VERSION', 'glibc 2.41'],
['GNU_LIBPTHREAD_VERSION', 'NPTL 2.41'],
['LOGNAME_MAX', '256'],
['PASS_MAX', '8192'],
['NSS_BUFLEN_GROUP', '1024'],
['NSS_BUFLEN_PASSWD', '1024'],
['UIO_MAXIOV', '1024'],
];
// The variables pathconf answers, which want a PATH operand.
const PATH_VARIABLES = new Set([
'FILESIZEBITS',
'LINK_MAX',
'MAX_CANON',
'MAX_INPUT',
'NAME_MAX',
'PATH_MAX',
'PIPE_BUF',
'POSIX2_SYMLINKS',
'POSIX_ALLOC_SIZE_MIN',
'POSIX_REC_INCR_XFER_SIZE',
'POSIX_REC_MAX_XFER_SIZE',
'POSIX_REC_MIN_XFER_SIZE',
'POSIX_REC_XFER_ALIGN',
'SYMLINK_MAX',
'_POSIX_CHOWN_RESTRICTED',
'_POSIX_NO_TRUNC',
'_POSIX_VDISABLE',
'_POSIX_ASYNC_IO',
'_POSIX_PRIO_IO',
'_POSIX_SYNC_IO',
'_POSIX_LINK_MAX',
'_POSIX_MAX_CANON',
'_POSIX_MAX_INPUT',
'_POSIX_NAME_MAX',
'_POSIX_PATH_MAX',
'_POSIX_PIPE_BUF',
'SOCK_MAXBUF',
]);
/**
* The table row a name selects: its own, or else the `_POSIX_` one it
* abbreviates (`getconf VERSION` is `_POSIX_VERSION`). Where a name has both,
* the two answer alike.
*/
function variable(name) {
return (GETCONF_VARIABLES.find(([row]) => row === name) ??
GETCONF_VARIABLES.find(([row]) => row.startsWith('_POSIX_') && row.slice(7) === name));
}
/** Whether the PATH operand names something pathconf could open. */
async function pathExists(ctx, word) {
const statPath = vfsStatPath(ctx.vfs);
if (statPath === undefined)
return true;
return (await statPath(PathSpec.fromStrPath(word, undefined, ctx.cwd))) !== null;
}
// `getconf`: one variable's value, or `-a` for all of them. A pathconf
// variable takes exactly one PATH and the rest none (else the usage block, exit
// 2); an unknown name is exit 2, a missing PATH exit 3, and `-v` is set aside
// as Debian's build does.
async function getconf(_accessor, _paths, texts, ctx) {
const fl = new FlagView(ctx.flags, specOf('getconf'));
const usage = [null, new IOResult({ exitCode: 2, stderr: ENC.encode(USAGE) })];
if (fl.asBool('a')) {
if (texts.length > 1)
return usage;
const found = await pathExists(ctx, texts[0] ?? '/');
const lines = GETCONF_VARIABLES.map(([name, value]) => name.padEnd(35) + (found || !PATH_VARIABLES.has(name) ? (value ?? '') : '') + '\n');
return [ENC.encode(lines.join('')), new IOResult()];
}
const asked = texts[0];
if (asked === undefined || texts.length > 2)
return usage;
const row = variable(asked);
if (row === undefined) {
const err = `getconf: Unrecognized variable \`${asked}'\n`;
return [null, new IOResult({ exitCode: 2, stderr: ENC.encode(err) })];
}
const [name, value] = row;
const path = texts[1];
if (PATH_VARIABLES.has(name) !== (path !== undefined))
return usage;
if (path !== undefined && !(await pathExists(ctx, path))) {
const err = `getconf: pathconf: ${path}: No such file or directory\n`;
return [null, new IOResult({ exitCode: 3, stderr: ENC.encode(err) })];
}
return [ENC.encode(`${value ?? UNDEFINED}\n`), new IOResult()];
}
export const GENERAL_GETCONF = command({
name: 'getconf',
vfs: null,
spec: specOf('getconf'),
fn: getconf,
});
//# sourceMappingURL=getconf.js.map