commit: 49c688001cc31952ffa01c7881a536128ac62f69
parent 7a7e5a55e44059a87f9fac2ee3a4b1939f06aba4
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Mon, 17 Mar 2025 18:32:53 +0100
cmd/getconf: new
Done because it turns out getconf(1) from Gentoo-musl & Alpine is incomplete.
Diffstat:
7 files changed, 801 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -9,6 +9,7 @@
!/cmd/*.ha
!/cmd/*.1
!/cmd/*.1.in
+!/cmd/*.m4
/cmd/expr.tab.c
*.t.err
*.o
diff --git a/Makefile b/Makefile
@@ -103,6 +103,14 @@ cmd/seq: cmd/seq.c Makefile
$(RM) -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno}
$(CC) -std=c99 $(CFLAGS) -o $@ cmd/seq.c -lm $(LDFLAGS) $(LDSTATIC)
+cmd/getconf_vars.h: cmd/getconf_vars.m4
+ $(M4) cmd/getconf_vars.m4 > cmd/getconf_vars.h
+
+# cmd/getconf_vars.h needs to invalidate cmd/getconf but not be in command
+cmd/getconf: cmd/getconf.c cmd/getconf_vars.h
+ $(RM) -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno}
+ $(CC) -std=c99 $(CFLAGS) -o cmd/getconf cmd/getconf.c $(LDFLAGS) $(LDSTATIC)
+
cmd/chmod: cmd/chmod.c lib/utils.a
cmd/chown: cmd/chown.c lib/utils.a
cmd/date: cmd/date.c lib/utils.a
diff --git a/cmd/getconf.1 b/cmd/getconf.1
@@ -0,0 +1,83 @@
+.\" utils-std: Collection of commonly available Unix tools
+.\" Copyright 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+.\" SPDX-License-Identifier: 0BSD
+.Dd March 17, 2025
+.Dt GETCONF 1
+.Os
+.Sh NAME
+.Nm getconf
+.Nd get configuration values
+.Sh SYNOPSIS
+.Nm
+.Ar system_var
+.Nm
+.Fl a
+.Nm
+.Ar path_var
+.Ar path
+.Nm
+.Fl a
+.Ar path
+.Sh DESCRIPTION
+In the first synopsis form,
+.Nm
+prints the system variable specified by the
+.Ar system_var
+operand.
+Which are obtained, in order, by:
+.Xr sysconf 3 ;
+.Xr confstr 3 ;
+.Xr limits.h 0 .
+.Pp
+In the second synopsis form,
+.Nm
+prints all the known system variables.
+.Pp
+In the third synopsis form,
+.Nm
+prints the variable specified by the
+.Ar path_var
+operand for the path specified by the
+.Ar path
+operand.
+Which are obtained via
+.Xr pathconf 3 .
+.Pp
+In the fourth synopsis form,
+.Nm
+prints all the known path variables for the path specified by the
+.Ar path
+operand.
+.Sh STDOUT
+If the specified variable is found, it is printed out as-is,
+when it isn't found but valid it is printed as "undefined".
+.Pp
+When using the
+.Fl a
+form,
+each variable is printed on a line in "name = value" format when found,
+and only as "name" when not found.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Getting the maximum amount of supplemental groups:
+.Dl Cm getconf NGROUPS_MAX
+.Pp
+Getting the maximum amount of bytes a filename can hold in
+the current directory:
+.Dl Cm getconf NAME_MAX ./
+.Sh SEE ALSO
+.Xr limits.h 0p ,
+.Xr confstr 3 ,
+.Xr pathconf 3 ,
+.Xr sysconf 3
+.Sh STANDARDS
+Except for it's lack of support of the
+.Fl v Ar specification
+argument,
+.Nm
+should be compliant with the
+IEEE Std 1003.1-2024 (“POSIX.1”)
+specification.
+.Sh AUTHORS
+.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/getconf.c b/cmd/getconf.c
@@ -0,0 +1,327 @@
+// utils-std: Collection of commonly available Unix tools
+// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+// SPDX-License-Identifier: MPL-2.0
+
+#define _POSIX_C_SOURCE 202405L
+#define _XOPEN_SOURCE 800
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h> // fputs
+#include <stdlib.h> // exit
+#include <string.h> // strerror
+#include <unistd.h> // getopt, pathconf
+
+// need to be after system headers
+#include "./getconf_vars.h"
+
+static int
+print_system_var(const char *var)
+{
+ for(size_t name = 0; name < (sizeof(confstr_vars) / sizeof(*confstr_vars)); name++)
+ {
+ if(strcmp(confstr_vars[name].name, var) != 0) continue;
+
+ errno = 0;
+ size_t buflen = confstr(confstr_vars[name].value, (char *)NULL, 0);
+ if(buflen == 0)
+ {
+ if(errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: confstr(%zd /* \"%s\" */, NULL, 0): %s\n",
+ name,
+ var,
+ strerror(errno));
+ return 1;
+ }
+
+ printf("undefined\n");
+ return 0;
+ }
+
+ errno = 0;
+ char *buf = malloc(buflen);
+ if(!buf)
+ {
+ fprintf(stderr,
+ "getconf: error: Failed to allocate %zd bytes buffer for confstr: %s\n",
+ buflen,
+ strerror(errno));
+ return 1;
+ }
+
+ errno = 0;
+ size_t ret = confstr(confstr_vars[name].value, buf, buflen);
+ if(ret == 0)
+ {
+ if(errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: confstr(%zd /* \"%s\" */, buf, %zd): %s\n",
+ name,
+ var,
+ buflen,
+ strerror(errno));
+ free(buf);
+ return 1;
+ }
+
+ printf("undefined\n");
+ free(buf);
+ return 0;
+ }
+
+ fwrite(buf, buflen, 1, stdout);
+ free(buf);
+ return 0;
+ }
+
+ for(size_t name = 0; name < (sizeof(sysconf_vars) / sizeof(*sysconf_vars)); name++)
+ {
+ if(strcmp(sysconf_vars[name].name, var) != 0) continue;
+
+ errno = 0;
+ long ret = sysconf((int)(sysconf_vars[name].value));
+ if(ret == -1 && errno != 0)
+ {
+ fprintf(
+ stderr, "getconf: error: sysconf(%zd /* \"%s\" */): %s\n", name, var, strerror(errno));
+ return 1;
+ }
+
+ if(ret == -1) ret = sysconf_vars[name].limit_h;
+
+ if(ret == -1)
+ {
+ printf("undefined\n");
+ return 0;
+ }
+
+ printf("%ld\n", ret);
+ return 0;
+ }
+
+ for(size_t name = 0; name < (sizeof(limits_vars) / sizeof(*limits_vars)); name++)
+ {
+ if(strcmp(limits_vars[name].name, var) != 0) continue;
+
+ long ret = limits_vars[name].limit_h;
+
+ if(ret == -1)
+ {
+ printf("undefined\n");
+ return 0;
+ }
+
+ printf("%ld\n", ret);
+ return 0;
+ }
+
+ fprintf(stderr, "getconf: error: unknown system_var \"%s\"\n", var);
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bool o_all = false;
+
+ int c = -1;
+ while((c = getopt(argc, argv, ":av:")) != -1)
+ {
+ switch(c)
+ {
+ case 'a':
+ o_all = true;
+ break;
+ case 'v':
+ fputs("getconf: -v option is unsupported\n", stderr);
+ return 1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(!o_all && argc == 1)
+ {
+ return print_system_var(argv[0]);
+ }
+ else if(o_all && argc == 0)
+ {
+ char *buf = NULL;
+ size_t buflen = 0;
+ for(size_t name = 0; name < (sizeof(confstr_vars) / sizeof(*confstr_vars)); name++)
+ {
+ errno = 0;
+ size_t buflen_ret = confstr(confstr_vars[name].value, (char *)NULL, 0);
+ if(buflen_ret == 0)
+ {
+ if(errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: confstr(%zd /* \"%s\" */, NULL, 0): %s\n",
+ name,
+ confstr_vars[name].name,
+ strerror(errno));
+ free(buf);
+ return 1;
+ }
+
+ /* undefined */
+ printf("%s\n", confstr_vars[name].name);
+ continue;
+ }
+
+ if(buflen_ret > buflen)
+ {
+ errno = 0;
+ char *buf_ret = realloc(buf, buflen_ret);
+ if(!buf_ret)
+ {
+ fprintf(stderr,
+ "getconf: error: Failed to allocate %zd bytes buffer for confstr: %s\n",
+ buflen,
+ strerror(errno));
+ free(buf);
+ return 1;
+ }
+ buflen = buflen_ret;
+ buf = buf_ret;
+ }
+
+ errno = 0;
+ size_t ret = confstr(confstr_vars[name].value, buf, buflen);
+ if(ret == 0)
+ {
+ if(errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: confstr(%zd /* \"%s\" */, buf, %zd): %s\n",
+ name,
+ confstr_vars[name].name,
+ buflen,
+ strerror(errno));
+ free(buf);
+ return 1;
+ }
+
+ /* undefined */
+ printf("%s\n", confstr_vars[name].name);
+ continue;
+ }
+
+ printf("%s = ", confstr_vars[name].name);
+ fwrite(buf, buflen_ret, 1, stdout);
+ printf("\n");
+ }
+
+ free(buf);
+
+ for(size_t name = 0; name < (sizeof(sysconf_vars) / sizeof(*sysconf_vars)); name++)
+ {
+ errno = 0;
+ long ret = sysconf((int)(sysconf_vars[name].value));
+ if(ret == -1 && errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: sysconf(%zd /* \"%s\" */): %s\n",
+ name,
+ argv[0],
+ strerror(errno));
+ return 1;
+ }
+
+ if(ret == -1) ret = sysconf_vars[name].limit_h;
+
+ if(ret == -1)
+ {
+ /* undefined */
+ printf("%s\n", sysconf_vars[name].name);
+ continue;
+ }
+
+ printf("%s = %ld\n", sysconf_vars[name].name, ret);
+ }
+
+ for(size_t name = 0; name < (sizeof(limits_vars) / sizeof(*limits_vars)); name++)
+ {
+ long ret = limits_vars[name].limit_h;
+
+ if(ret == -1)
+ {
+ /* undefined */
+ printf("%s\n", limits_vars[name].name);
+ continue;
+ }
+
+ printf("%s = %ld\n", limits_vars[name].name, ret);
+ }
+
+ return 0;
+ }
+ else if(!o_all && argc == 2)
+ {
+ for(size_t name = 0; name < (sizeof(pathconf_vars) / sizeof(*pathconf_vars)); name++)
+ {
+ if(strcmp(pathconf_vars[name].name, argv[0]) != 0) continue;
+
+ errno = 0;
+ long ret = pathconf(argv[1], (int)(pathconf_vars[name].value));
+ if(ret == -1 && errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: pathconf(\"%s\", %zd /* \"%s\" */): %s\n",
+ argv[1],
+ name,
+ argv[0],
+ strerror(errno));
+ return 1;
+ }
+ if(ret == -1) ret = sysconf_vars[name].limit_h;
+
+ printf("%ld\n", ret);
+ return 0;
+ }
+
+ fprintf(stderr, "getconf: error: unknown path_var \"%s\"\n", argv[0]);
+ return 1;
+ }
+ else if(o_all && argc == 1)
+ {
+ for(size_t name = 0; name < (sizeof(pathconf_vars) / sizeof(*pathconf_vars)); name++)
+ {
+ errno = 0;
+ long ret = pathconf(argv[1], (int)(pathconf_vars[name].value));
+ if(ret == -1 && errno != 0)
+ {
+ fprintf(stderr,
+ "getconf: error: pathconf(\"%s\", %zd /* \"%s\" */): %s\n",
+ argv[1],
+ name,
+ argv[0],
+ strerror(errno));
+ return 1;
+ }
+ if(ret == -1) ret = sysconf_vars[name].limit_h;
+
+ printf("%s = %ld\n", pathconf_vars[name].name, ret);
+ }
+
+ return 0;
+ }
+ else
+ {
+ fprintf(stderr, "getconf: error: wrong number of arguments\n");
+ fprintf(stderr, "\
+Usage: getconf <system_var>\n\
+ getconf -a\n\
+ getconf <path_var> <path>\n\
+ getconf -a <path>\n\
+");
+ return 1;
+ }
+}
diff --git a/cmd/getconf_vars.m4 b/cmd/getconf_vars.m4
@@ -0,0 +1,380 @@
+dnl utils-std: Collection of commonly available Unix tools
+dnl SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+dnl SPDX-License-Identifier: MPL-2.0
+dnl
+dnl Usage: m4 cmd/getconf_vars.m4 > cmd/getconf_vars.h
+dnl
+define(`conf_var', ` {$1, $2, -1},')dnl
+define(`conf_var_limit', `#ifndef $3
+#define $3 -1
+#endif
+ {$1, $2, $3},
+')dnl
+
+struct conf_vars
+{
+ const char *name;
+ const int value;
+ const long limit_h;
+};
+
+struct limits
+{
+ const char *name;
+ const long limit_h;
+};
+
+dnl _CS_V${n}_ENV exposes environment variables to achieve said SUSv${n} version
+dnl It's therefore dependent on what the underlying system supports.
+define(`confstr_var', `#ifdef _CS_$1
+ {"$1", _CS_$1, -1},
+#endif')dnl
+// confstr(3) variables without the _CS_ prefix
+static const struct conf_vars confstr_vars[] = {
+conf_var("PATH", _CS_PATH)
+
+confstr_var(POSIX_V8_ILP32_OFF32_CFLAGS)
+confstr_var(POSIX_V8_ILP32_OFF32_LDFLAGS)
+confstr_var(POSIX_V8_ILP32_OFF32_LIBS)
+confstr_var(POSIX_V8_ILP32_OFFBIG_CFLAGS)
+confstr_var(POSIX_V8_ILP32_OFFBIG_LDFLAGS)
+confstr_var(POSIX_V8_ILP32_OFFBIG_LIBS)
+confstr_var(POSIX_V8_LP64_OFF64_CFLAGS)
+confstr_var(POSIX_V8_LP64_OFF64_LDFLAGS)
+confstr_var(POSIX_V8_LP64_OFF64_LIBS)
+confstr_var(POSIX_V8_LPBIG_OFFBIG_CFLAGS)
+confstr_var(POSIX_V8_LPBIG_OFFBIG_LDFLAGS)
+confstr_var(POSIX_V8_LPBIG_OFFBIG_LIBS)
+confstr_var(POSIX_V8_THREADS_CFLAGS)
+confstr_var(POSIX_V8_THREADS_LDFLAGS)
+confstr_var(POSIX_V8_WIDTH_RESTRICTED_ENVS)
+confstr_var(V8_ENV)
+
+confstr_var(POSIX_V7_ILP32_OFF32_CFLAGS)
+confstr_var(POSIX_V7_ILP32_OFF32_LDFLAGS)
+confstr_var(POSIX_V7_ILP32_OFF32_LIBS)
+confstr_var(POSIX_V7_ILP32_OFFBIG_CFLAGS)
+confstr_var(POSIX_V7_ILP32_OFFBIG_LDFLAGS)
+confstr_var(POSIX_V7_ILP32_OFFBIG_LIBS)
+confstr_var(POSIX_V7_LP64_OFF64_CFLAGS)
+confstr_var(POSIX_V7_LP64_OFF64_LDFLAGS)
+confstr_var(POSIX_V7_LP64_OFF64_LIBS)
+confstr_var(POSIX_V7_LPBIG_OFFBIG_CFLAGS)
+confstr_var(POSIX_V7_LPBIG_OFFBIG_LDFLAGS)
+confstr_var(POSIX_V7_LPBIG_OFFBIG_LIBS)
+confstr_var(POSIX_V7_THREADS_CFLAGS)
+confstr_var(POSIX_V7_THREADS_LDFLAGS)
+confstr_var(POSIX_V7_WIDTH_RESTRICTED_ENVS)
+confstr_var(V7_ENV)
+
+confstr_var(POSIX_V6_ILP32_OFF32_CFLAGS)
+confstr_var(POSIX_V6_ILP32_OFF32_LDFLAGS)
+confstr_var(POSIX_V6_ILP32_OFF32_LIBS)
+confstr_var(POSIX_V6_ILP32_OFFBIG_CFLAGS)
+confstr_var(POSIX_V6_ILP32_OFFBIG_LDFLAGS)
+confstr_var(POSIX_V6_ILP32_OFFBIG_LIBS)
+confstr_var(POSIX_V6_LP64_OFF64_CFLAGS)
+confstr_var(POSIX_V6_LP64_OFF64_LDFLAGS)
+confstr_var(POSIX_V6_LP64_OFF64_LIBS)
+confstr_var(POSIX_V6_LPBIG_OFFBIG_CFLAGS)
+confstr_var(POSIX_V6_LPBIG_OFFBIG_LDFLAGS)
+confstr_var(POSIX_V6_LPBIG_OFFBIG_LIBS)
+confstr_var(POSIX_V6_WIDTH_RESTRICTED_ENVS)
+confstr_var(V6_ENV)
+};
+
+static const struct conf_vars pathconf_vars[] = {
+conf_var_limit("FILESIZEBITS", _PC_FILESIZEBITS, FILESIZEBITS)
+conf_var_limit("LINK_MAX", _PC_LINK_MAX, LINK_MAX)
+conf_var_limit("MAX_CANON", _PC_MAX_CANON, MAX_CANON)
+conf_var_limit("MAX_INPUT", _PC_MAX_INPUT, MAX_INPUT)
+conf_var_limit("NAME_MAX", _PC_NAME_MAX, NAME_MAX)
+conf_var_limit("PATH_MAX", _PC_PATH_MAX, PATH_MAX)
+conf_var_limit("PIPE_BUF", _PC_PIPE_BUF, PIPE_BUF)
+conf_var_limit("POSIX2_SYMLINKS", _PC_2_SYMLINKS, POSIX2_SYMLINKS)
+conf_var_limit("POSIX_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN, POSIX_ALLOC_SIZE_MIN)
+conf_var_limit("POSIX_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE, POSIX_REC_INCR_XFER_SIZE)
+conf_var_limit("POSIX_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE, POSIX_REC_MAX_XFER_SIZE)
+conf_var_limit("POSIX_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE, POSIX_REC_MIN_XFER_SIZE)
+conf_var_limit("POSIX_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN, POSIX_REC_XFER_ALIGN)
+conf_var_limit("SYMLINK_MAX", _PC_SYMLINK_MAX, SYMLINK_MAX)
+#ifdef _PC_TEXTDOMAIN_MAX
+conf_var_limit("TEXTDOMAIN_MAX", _PC_TEXTDOMAIN_MAX, TEXTDOMAIN_MAX)
+#endif
+conf_var("_POSIX_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED)
+conf_var("_POSIX_NO_TRUNC", _PC_NO_TRUNC)
+conf_var("_POSIX_VDISABLE", _PC_VDISABLE)
+conf_var("_POSIX_ASYNC_IO", _PC_ASYNC_IO)
+#ifdef _PC_FALLOC
+conf_var("_POSIX_FALLOC", _PC_FALLOC)
+#endif
+conf_var("_POSIX_PRIO_IO", _PC_PRIO_IO)
+conf_var("_POSIX_SYNC_IO", _PC_SYNC_IO)
+#ifdef _PC_TIMESTAMP_RESOLUTION
+conf_var("_POSIX_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION)
+#endif
+};
+
+static const struct conf_vars sysconf_vars[] = {
+conf_var_limit("AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX, AIO_LISTIO_MAX)
+conf_var_limit("AIO_MAX", _SC_AIO_MAX, AIO_MAX)
+conf_var_limit("AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX, AIO_PRIO_DELTA_MAX)
+conf_var_limit("ARG_MAX", _SC_ARG_MAX, ARG_MAX)
+conf_var_limit("ATEXIT_MAX", _SC_ATEXIT_MAX, ATEXIT_MAX)
+conf_var_limit("BC_BASE_MAX", _SC_BC_BASE_MAX, BC_BASE_MAX)
+conf_var_limit("BC_DIM_MAX", _SC_BC_DIM_MAX, BC_DIM_MAX)
+conf_var_limit("BC_SCALE_MAX", _SC_BC_SCALE_MAX, BC_SCALE_MAX)
+conf_var_limit("BC_STRING_MAX", _SC_BC_STRING_MAX, BC_STRING_MAX)
+conf_var_limit("CHILD_MAX", _SC_CHILD_MAX, CHILD_MAX)
+ // name not in POSIX.1-2024 but value is
+conf_var("CLK_TCK", _SC_CLK_TCK)
+conf_var_limit("COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX, COLL_WEIGHTS_MAX)
+conf_var_limit("DELAYTIMER_MAX", _SC_DELAYTIMER_MAX, DELAYTIMER_MAX)
+conf_var_limit("EXPR_NEST_MAX", _SC_EXPR_NEST_MAX, EXPR_NEST_MAX)
+conf_var_limit("HOST_NAME_MAX", _SC_HOST_NAME_MAX, HOST_NAME_MAX)
+conf_var_limit("IOV_MAX", _SC_IOV_MAX, IOV_MAX)
+conf_var_limit("LINE_MAX", _SC_LINE_MAX, LINE_MAX)
+conf_var_limit("LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX, LOGIN_NAME_MAX)
+conf_var_limit("NGROUPS_MAX", _SC_NGROUPS_MAX, NGROUPS_MAX)
+ // name not in POSIX.1-2024 but value is
+conf_var("GETGR_R_SIZE_MAX", _SC_GETGR_R_SIZE_MAX)
+ // name not in POSIX.1-2024 but value is
+conf_var("GETPW_R_SIZE_MAX", _SC_GETPW_R_SIZE_MAX)
+conf_var_limit("MQ_OPEN_MAX", _SC_MQ_OPEN_MAX, MQ_OPEN_MAX)
+conf_var_limit("MQ_PRIO_MAX", _SC_MQ_PRIO_MAX, MQ_PRIO_MAX)
+#ifdef _SC_NPROCESSORS_CONF // added in POSIX.1-2024
+ // name not in POSIX.1-2024 but value is
+conf_var("NPROCESSORS_CONF", _SC_NPROCESSORS_CONF)
+#endif
+#ifdef _SC_NPROCESSORS_ONLN // added in POSIX.1-2024
+ // name not in POSIX.1-2024 but value is
+conf_var("NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN)
+#endif
+#ifdef _SC_NSIG // added in POSIX.1-2024
+ // name not in POSIX.1-2024 but value is
+# ifdef NSIG
+conf_var_limit("NSIG", _SC_NSIG, NSIG)
+# else
+conf_var("NSIG", _SC_NSIG)
+# endif
+#endif
+conf_var_limit("OPEN_MAX", _SC_OPEN_MAX, OPEN_MAX)
+conf_var_limit("PAGE_SIZE", _SC_PAGE_SIZE, PAGE_SIZE)
+conf_var_limit("PAGESIZE", _SC_PAGESIZE, PAGESIZE)
+conf_var_limit("PTHREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS, PTHREAD_DESTRUCTOR_ITERATIONS)
+conf_var_limit("PTHREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX, PTHREAD_KEYS_MAX)
+conf_var_limit("PTHREAD_STACK_MIN", _SC_THREAD_STACK_MIN, PTHREAD_STACK_MIN)
+conf_var_limit("PTHREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX, PTHREAD_THREADS_MAX)
+conf_var_limit("RE_DUP_MAX", _SC_RE_DUP_MAX, RE_DUP_MAX)
+conf_var_limit("RTSIG_MAX", _SC_RTSIG_MAX, RTSIG_MAX)
+conf_var_limit("SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX, SEM_NSEMS_MAX)
+conf_var_limit("SEM_VALUE_MAX", _SC_SEM_VALUE_MAX, SEM_VALUE_MAX)
+conf_var_limit("SIGQUEUE_MAX", _SC_SIGQUEUE_MAX, SIGQUEUE_MAX)
+conf_var_limit("STREAM_MAX", _SC_STREAM_MAX, STREAM_MAX)
+conf_var_limit("SYMLOOP_MAX", _SC_SYMLOOP_MAX, SYMLOOP_MAX)
+conf_var_limit("TIMER_MAX", _SC_TIMER_MAX, TIMER_MAX)
+conf_var_limit("TTY_NAME_MAX", _SC_TTY_NAME_MAX, TTY_NAME_MAX)
+conf_var_limit("TZNAME_MAX", _SC_TZNAME_MAX, TZNAME_MAX)
+conf_var("_POSIX_ADVISORY_INFO", _SC_ADVISORY_INFO)
+conf_var("_POSIX_BARRIERS", _SC_BARRIERS)
+conf_var("_POSIX_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO)
+conf_var("_POSIX_CLOCK_SELECTION", _SC_CLOCK_SELECTION)
+conf_var("_POSIX_CPUTIME", _SC_CPUTIME)
+#ifdef _SC_DEVICE_CONTROL // added in POSIX.1-2024
+conf_var("_POSIX_DEVICE_CONTROL", _SC_DEVICE_CONTROL)
+#endif
+conf_var("_POSIX_FSYNC", _SC_FSYNC)
+conf_var("_POSIX_IPV6", _SC_IPV6)
+conf_var("_POSIX_JOB_CONTROL", _SC_JOB_CONTROL)
+conf_var("_POSIX_MAPPED_FILES", _SC_MAPPED_FILES)
+conf_var("_POSIX_MEMLOCK", _SC_MEMLOCK)
+conf_var("_POSIX_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE)
+conf_var("_POSIX_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION)
+conf_var("_POSIX_MESSAGE_PASSING", _SC_MESSAGE_PASSING)
+conf_var("_POSIX_MONOTONIC_CLOCK", _SC_MONOTONIC_CLOCK)
+conf_var("_POSIX_PRIORITIZED_IO", _SC_PRIORITIZED_IO)
+conf_var("_POSIX_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING)
+conf_var("_POSIX_RAW_SOCKETS", _SC_RAW_SOCKETS)
+conf_var("_POSIX_READER_WRITER_LOCKS", _SC_READER_WRITER_LOCKS)
+conf_var("_POSIX_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS)
+conf_var("_POSIX_REGEXP", _SC_REGEXP)
+conf_var("_POSIX_SAVED_IDS", _SC_SAVED_IDS)
+conf_var("_POSIX_SEMAPHORES", _SC_SEMAPHORES)
+conf_var("_POSIX_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS)
+conf_var("_POSIX_SHELL", _SC_SHELL)
+conf_var("_POSIX_SPAWN", _SC_SPAWN)
+conf_var("_POSIX_SPIN_LOCKS", _SC_SPIN_LOCKS)
+conf_var("_POSIX_SPORADIC_SERVER", _SC_SPORADIC_SERVER)
+conf_var("_POSIX_SS_REPL_MAX", _SC_SS_REPL_MAX)
+conf_var("_POSIX_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO)
+conf_var("_POSIX_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR)
+conf_var("_POSIX_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE)
+conf_var("_POSIX_THREAD_CPUTIME", _SC_THREAD_CPUTIME)
+conf_var("_POSIX_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT)
+conf_var("_POSIX_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT)
+conf_var("_POSIX_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING)
+conf_var("_POSIX_THREAD_PROCESS_SHARED", _SC_THREAD_PROCESS_SHARED)
+conf_var("_POSIX_THREAD_ROBUST_PRIO_INHERIT", _SC_THREAD_ROBUST_PRIO_INHERIT)
+conf_var("_POSIX_THREAD_ROBUST_PRIO_PROTECT", _SC_THREAD_ROBUST_PRIO_PROTECT)
+conf_var("_POSIX_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS)
+conf_var("_POSIX_THREAD_SPORADIC_SERVER", _SC_THREAD_SPORADIC_SERVER)
+conf_var("_POSIX_THREADS", _SC_THREADS)
+conf_var("_POSIX_TIMEOUTS", _SC_TIMEOUTS)
+conf_var("_POSIX_TIMERS", _SC_TIMERS)
+conf_var("_POSIX_TYPED_MEMORY_OBJECTS", _SC_TYPED_MEMORY_OBJECTS)
+conf_var("_POSIX_VERSION", _SC_VERSION)
+#ifdef _SC_V8_ILP32_OFF32 // added in POSIX.1-2024
+conf_var("_POSIX_V8_ILP32_OFF32", _SC_V8_ILP32_OFF32)
+#endif
+#ifdef _SC_V8_ILP32_OFFBIG // added in POSIX.1-2024
+conf_var("_POSIX_V8_ILP32_OFFBIG", _SC_V8_ILP32_OFFBIG)
+#endif
+#ifdef _SC_V8_LP64_OFF64 // added in POSIX.1-2024
+conf_var("_POSIX_V8_LP64_OFF64", _SC_V8_LP64_OFF64)
+#endif
+#ifdef _SC_V8_LPBIG_OFFBIG // added in POSIX.1-2024
+conf_var("_POSIX_V8_LPBIG_OFFBIG", _SC_V8_LPBIG_OFFBIG)
+#endif
+#ifdef _SC_V7_ILP32_OFF32 // Obsolescent in POSIX.1-2024
+conf_var("_POSIX_V7_ILP32_OFF32", _SC_V7_ILP32_OFF32)
+#endif
+conf_var("_POSIX_V7_ILP32_OFFBIG", _SC_V7_ILP32_OFFBIG)
+conf_var("_POSIX_V7_LP64_OFF64", _SC_V7_LP64_OFF64)
+conf_var("_POSIX_V7_LPBIG_OFFBIG", _SC_V7_LPBIG_OFFBIG)
+// For compatibility with earlier versions, the following variable names shall also be supported: POSIX2_C_BIND POSIX2_C_DEV POSIX2_CHAR_TERM POSIX2_FORT_RUN POSIX2_LOCALEDEF POSIX2_SW_DEV POSIX2_UPE POSIX2_VERSION
+conf_var("POSIX2_C_BIND", _SC_2_C_BIND)
+conf_var("_POSIX2_C_BIND", _SC_2_C_BIND)
+conf_var("POSIX2_C_DEV", _SC_2_C_DEV)
+conf_var("_POSIX2_C_DEV", _SC_2_C_DEV)
+conf_var("POSIX2_CHAR_TERM", _SC_2_CHAR_TERM)
+conf_var("_POSIX2_CHAR_TERM", _SC_2_CHAR_TERM)
+conf_var("POSIX2_FORT_RUN", _SC_2_FORT_RUN)
+conf_var("_POSIX2_FORT_RUN", _SC_2_FORT_RUN)
+conf_var("POSIX2_LOCALEDEF", _SC_2_LOCALEDEF)
+conf_var("_POSIX2_LOCALEDEF", _SC_2_LOCALEDEF)
+conf_var("POSIX2_SW_DEV", _SC_2_SW_DEV)
+conf_var("_POSIX2_SW_DEV", _SC_2_SW_DEV)
+conf_var("POSIX2_UPE", _SC_2_UPE)
+conf_var("_POSIX2_UPE", _SC_2_UPE)
+conf_var("POSIX2_VERSION", _SC_2_VERSION)
+conf_var("_POSIX2_VERSION", _SC_2_VERSION)
+conf_var("_XOPEN_CRYPT", _SC_XOPEN_CRYPT)
+conf_var("_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N)
+conf_var("_XOPEN_REALTIME", _SC_XOPEN_REALTIME)
+conf_var("_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS)
+conf_var("_XOPEN_SHM", _SC_XOPEN_SHM)
+conf_var("_XOPEN_UNIX", _SC_XOPEN_UNIX)
+conf_var("XOPEN_UNIX", _SC_XOPEN_UNIX)
+#ifdef _SC_XOPEN_UUCP // added in POSIX.1-2008, strangely missing from musl
+conf_var("_XOPEN_UUCP", _SC_XOPEN_UUCP)
+conf_var("XOPEN_UUCP", _SC_XOPEN_UUCP)
+#endif
+conf_var("_XOPEN_VERSION", _SC_XOPEN_VERSION)
+#ifdef _SC_CHARCLASS_NAME_MAX
+/* https://www.austingroupbugs.net/view.php?id=1912 - sysconf lacks variable for {CHARCLASS_NAME_MAX} */
+conf_var_limit("CHARCLASS_NAME_MAX", _SC_CHARCLASS_NAME_MAX, CHARCLASS_NAME_MAX)
+#endif
+};
+
+define(`limits_var', `#ifdef $1
+ {"$1", $1},
+#endif')dnl
+define(`limits_var_alias', `#ifdef $2
+ {"$1", $2},
+#endif')dnl
+// _MIN and _MAX from <limits.h>
+static const struct limits limits_vars[] = {
+limits_var(SS_REPL_MAX)
+#ifndef _PC_TEXTDOMAIN_MAX
+limits_var(TEXTDOMAIN_MAX)
+#endif
+#ifndef _SC_CHARCLASS_NAME_MAX
+limits_var(CHARCLASS_NAME_MAX)
+#endif
+limits_var(_POSIX_CLOCKRES_MIN)
+limits_var(_POSIX_AIO_LISTIO_MAX)
+limits_var(_POSIX_AIO_MAX)
+limits_var(_POSIX_ARG_MAX)
+limits_var(_POSIX_CHILD_MAX)
+limits_var(_POSIX_DELAYTIMER_MAX)
+limits_var(_POSIX_HOST_NAME_MAX)
+limits_var(_POSIX_LINK_MAX)
+limits_var(_POSIX_LOGIN_NAME_MAX)
+limits_var(_POSIX_MAX_CANON)
+limits_var(_POSIX_MAX_INPUT)
+limits_var(_POSIX_MQ_OPEN_MAX)
+limits_var(_POSIX_MQ_PRIO_MAX)
+limits_var(_POSIX_NAME_MAX)
+limits_var(_POSIX_NGROUPS_MAX)
+limits_var(_POSIX_OPEN_MAX)
+limits_var(_POSIX_PATH_MAX)
+limits_var(_POSIX_PIPE_BUF)
+limits_var(_POSIX_RE_DUP_MAX)
+limits_var(_POSIX_RTSIG_MAX)
+limits_var(_POSIX_SEM_NSEMS_MAX)
+limits_var(_POSIX_SEM_VALUE_MAX)
+limits_var(_POSIX_SIGQUEUE_MAX)
+limits_var(_POSIX_SSIZE_MAX)
+limits_var(_POSIX_SS_REPL_MAX)
+limits_var(_POSIX_STREAM_MAX)
+limits_var(_POSIX_SYMLINK_MAX)
+limits_var(_POSIX_SYMLOOP_MAX)
+limits_var(_POSIX_THREAD_DESTRUCTOR_ITERATIONS)
+limits_var(_POSIX_THREAD_KEYS_MAX)
+limits_var(_POSIX_THREAD_THREADS_MAX)
+limits_var(_POSIX_TIMER_MAX)
+limits_var(_POSIX_TTY_NAME_MAX)
+limits_var(_POSIX_TZNAME_MAX)
+limits_var(_POSIX2_BC_BASE_MAX)
+limits_var(_POSIX2_BC_DIM_MAX)
+limits_var(_POSIX2_BC_SCALE_MAX)
+limits_var(_POSIX2_BC_STRING_MAX)
+limits_var(_POSIX2_CHARCLASS_NAME_MAX)
+limits_var(_POSIX2_COLL_WEIGHTS_MAX)
+limits_var(_POSIX2_EXPR_NEST_MAX)
+limits_var(_POSIX2_LINE_MAX)
+limits_var(_POSIX2_RE_DUP_MAX)
+limits_var(_XOPEN_IOV_MAX)
+limits_var(_XOPEN_NAME_MAX)
+limits_var(_XOPEN_PATH_MAX)
+limits_var(CHAR_BIT)
+limits_var(CHAR_MAX)
+limits_var(CHAR_MIN)
+limits_var(INT_MAX)
+limits_var(INT_MIN)
+limits_var(LLONG_MAX)
+limits_var(LLONG_MIN)
+limits_var(LONG_BIT)
+limits_var(LONG_MAX)
+limits_var(LONG_MIN)
+limits_var(MB_LEN_MAX)
+limits_var(SCHAR_MAX)
+limits_var(SCHAR_MIN)
+limits_var(SHRT_MAX)
+limits_var(SHRT_MIN)
+limits_var(SSIZE_MAX)
+limits_var(UCHAR_MAX)
+limits_var(UINT_MAX)
+limits_var(ULLONG_MAX)
+limits_var(ULONG_MAX)
+limits_var(USHRT_MAX)
+limits_var(WORD_BIT)
+limits_var(GETENTROPY_MAX)
+limits_var(NL_ARGMAX)
+limits_var(NL_LANGMAX)
+limits_var(NL_MSGMAX)
+limits_var(NL_SETMAX)
+limits_var(NL_TEXTMAX)
+limits_var(NSIG_MAX)
+limits_var(NZERO)
+limits_var(NSIG_MAX)
+// For compatibility with earlier versions, the following variable names shall also be supported: POSIX2_BC_BASE_MAX POSIX2_BC_DIM_MAX POSIX2_BC_SCALE_MAX POSIX2_BC_STRING_MAX POSIX2_COLL_WEIGHTS_MAX POSIX2_EXPR_NEST_MAX POSIX2_LINE_MAX POSIX2_RE_DUP_MAX
+limits_var_alias(POSIX2_BC_BASE_MAX, _POSIX2_BC_BASE_MAX)
+limits_var_alias(POSIX2_BC_DIM_MAX, _POSIX2_BC_DIM_MAX)
+limits_var_alias(POSIX2_BC_SCALE_MAX, _POSIX2_BC_SCALE_MAX)
+limits_var_alias(POSIX2_BC_STRING_MAX, _POSIX2_BC_STRING_MAX)
+limits_var_alias(POSIX2_COLL_WEIGHTS_MAX, _POSIX2_COLL_WEIGHTS_MAX)
+limits_var_alias(POSIX2_EXPR_NEST_MAX, _POSIX2_EXPR_NEST_MAX)
+limits_var_alias(POSIX2_LINE_MAX, _POSIX2_LINE_MAX)
+limits_var_alias(POSIX2_RE_DUP_MAX, _POSIX2_RE_DUP_MAX)
+};
diff --git a/lsb_commands.txt b/lsb_commands.txt
@@ -42,7 +42,7 @@ find: out of scope
fold: ?
fuser: ?
gencat: out of scope
-getconf: Maybe
+getconf: done
gettext: out of scope
grep: out of scope
groupadd: out of scope
diff --git a/posix_utilities.txt b/posix_utilities.txt
@@ -54,7 +54,7 @@ fold: no, toolchain
fuser
gencat: no, external
get: no, SCCS XOPEN_UNIX
-getconf: NetBSD getconf adapted for musl by Alpine is okay
+getconf: done
getopts: no, sh built-in
gettext: no, external
grep