1/* getconf.c - get configuration values 2 * 3 * Copyright 2017 Rob Landley <rob@landley.net> 4 * 5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.c 6 * 7 * Deviations from posix: no -v because nothing says what it should DO. 8 * Added -l, what symbols should be included is a bit unclear. 9 * Added -a, copied FSF behavior of assuming "/" if no path supplied. 10 11USE_GETCONF(NEWTOY(getconf, ">2al", TOYFLAG_USR|TOYFLAG_BIN)) 12 13config GETCONF 14 bool "getconf" 15 default y 16 help 17 usage: getconf -a [PATH] | -l | NAME [PATH] 18 19 Get system configuration values. Values from pathconf(3) require a path. 20 21 -a Show all (defaults to "/" if no path given) 22 -l List available value names (grouped by source) 23*/ 24 25#define FOR_getconf 26#include "toys.h" 27#include <limits.h> 28 29// This is missing on glibc (bionic has it). 30#ifndef _SC_XOPEN_UUCP 31#define _SC_XOPEN_UUCP -1 32#endif 33 34#ifdef __APPLE__ 35// macOS doesn't have a bunch of stuff. The actual macOS getconf says 36// "no such parameter", but -- unless proven otherwise -- it seems more useful 37// for portability if we act like we understood but say "undefined"? 38#define _SC_AVPHYS_PAGES -1 39#define _SC_THREAD_ROBUST_PRIO_INHERIT -1 40#define _SC_THREAD_ROBUST_PRIO_PROTECT -1 41#define _SC_UIO_MAXIOV -1 42#define _SC_V7_ILP32_OFF32 -1 43#define _SC_V7_ILP32_OFFBIG -1 44#define _SC_V7_LP64_OFF64 -1 45#define _SC_V7_LPBIG_OFFBIG -1 46#define _CS_V7_ENV -1 47#endif 48 49struct config { 50 char *name; 51 long long value; 52}; 53 54// Lists of symbols getconf can query, broken down by whether we call sysconf(), 55// confstr(), or output the macro value directly. 56 57// Probe the live system 58struct config sysconfs[] = { 59 /* POSIX */ 60#define CONF(n) {"_POSIX_" #n,_SC_ ## n} 61 CONF(ADVISORY_INFO), CONF(BARRIERS), CONF(ASYNCHRONOUS_IO), 62 CONF(CLOCK_SELECTION), CONF(CPUTIME), CONF(FSYNC), CONF(IPV6), 63 CONF(JOB_CONTROL), CONF(MAPPED_FILES), CONF(MEMLOCK), CONF(MEMLOCK_RANGE), 64 CONF(MEMORY_PROTECTION), CONF(MESSAGE_PASSING), CONF(MONOTONIC_CLOCK), 65 CONF(PRIORITY_SCHEDULING), CONF(RAW_SOCKETS), CONF(READER_WRITER_LOCKS), 66 CONF(REALTIME_SIGNALS), CONF(REGEXP), CONF(SAVED_IDS), CONF(SEMAPHORES), 67 CONF(SHARED_MEMORY_OBJECTS), CONF(SHELL), CONF(SPAWN), CONF(SPIN_LOCKS), 68 CONF(SPORADIC_SERVER), CONF(SS_REPL_MAX), CONF(SYNCHRONIZED_IO), 69 CONF(THREAD_ATTR_STACKADDR), CONF(THREAD_ATTR_STACKSIZE), 70 CONF(THREAD_CPUTIME), CONF(THREAD_PRIO_INHERIT), CONF(THREAD_PRIO_PROTECT), 71 CONF(THREAD_PRIORITY_SCHEDULING), CONF(THREAD_PROCESS_SHARED), 72 CONF(THREAD_ROBUST_PRIO_INHERIT), CONF(THREAD_ROBUST_PRIO_PROTECT), 73 CONF(THREAD_SAFE_FUNCTIONS), CONF(THREAD_SPORADIC_SERVER), CONF(THREADS), 74 CONF(TIMEOUTS), CONF(TIMERS), CONF(TRACE), CONF(TRACE_EVENT_FILTER), 75 CONF(TRACE_EVENT_NAME_MAX), CONF(TRACE_INHERIT), CONF(TRACE_LOG), 76 CONF(TRACE_NAME_MAX), CONF(TRACE_SYS_MAX), CONF(TRACE_USER_EVENT_MAX), 77 CONF(TYPED_MEMORY_OBJECTS), CONF(VERSION), CONF(V7_ILP32_OFF32), 78 CONF(V7_ILP32_OFFBIG), CONF(V7_LP64_OFF64), CONF(V7_LPBIG_OFFBIG), 79 80 /* POSIX.2 */ 81#undef CONF 82#define CONF(n) {"POSIX2_" #n,_SC_2_ ## n} 83 CONF(C_BIND), CONF(C_DEV), CONF(CHAR_TERM), CONF(FORT_DEV), CONF(FORT_RUN), 84 CONF(LOCALEDEF), CONF(PBS), CONF(PBS_ACCOUNTING), CONF(PBS_CHECKPOINT), 85 CONF(PBS_LOCATE), CONF(PBS_MESSAGE), CONF(PBS_TRACK), CONF(SW_DEV), 86 CONF(UPE), CONF(VERSION), 87 88 /* X/Open */ 89#undef CONF 90#define CONF(n) {"_XOPEN_" #n,_SC_XOPEN_ ## n} 91 CONF(CRYPT), CONF(ENH_I18N), CONF(REALTIME), CONF(REALTIME_THREADS), 92 CONF(SHM), CONF(STREAMS), CONF(UNIX), CONF(UUCP), CONF(VERSION), 93 94 /* No obvious standard */ 95#undef CONF 96#define CONF(n) {#n,_SC_ ## n} 97 CONF(AIO_LISTIO_MAX), CONF(AIO_MAX), CONF(AIO_PRIO_DELTA_MAX), CONF(ARG_MAX), 98 CONF(ATEXIT_MAX), CONF(BC_BASE_MAX), CONF(BC_DIM_MAX), CONF(BC_SCALE_MAX), 99 CONF(BC_STRING_MAX), CONF(CHILD_MAX), CONF(CLK_TCK), CONF(COLL_WEIGHTS_MAX), 100 CONF(DELAYTIMER_MAX), CONF(EXPR_NEST_MAX), CONF(HOST_NAME_MAX), 101 CONF(IOV_MAX), CONF(LINE_MAX), CONF(LOGIN_NAME_MAX), CONF(NGROUPS_MAX), 102 CONF(MQ_OPEN_MAX), CONF(MQ_PRIO_MAX), CONF(OPEN_MAX), CONF(PAGE_SIZE), 103 CONF(PAGESIZE), CONF(RAW_SOCKETS), CONF(RE_DUP_MAX), CONF(RTSIG_MAX), 104 CONF(SEM_NSEMS_MAX), CONF(SEM_VALUE_MAX), CONF(SIGQUEUE_MAX), 105 CONF(STREAM_MAX), CONF(SYMLOOP_MAX), CONF(TIMER_MAX), CONF(TTY_NAME_MAX), 106 CONF(TZNAME_MAX), CONF(UIO_MAXIOV), 107 108 /* Names that just don't match the symbol, do it by hand */ 109 {"_AVPHYS_PAGES", _SC_AVPHYS_PAGES}, {"_PHYS_PAGES", _SC_PHYS_PAGES}, 110 {"_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF}, 111 {"_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN}, 112 113 /* There's a weird "PTHREAD" vs "THREAD" mismatch here. */ 114 {"PTHREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS}, 115 {"PTHREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX}, 116 {"PTHREAD_STACK_MIN", _SC_THREAD_STACK_MIN}, 117 {"PTHREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX}, 118}; 119 120// Probe the live system with a path 121struct config pathconfs[] = { 122#undef CONF 123#define CONF(n) {#n,_PC_ ## n} 124 CONF(ASYNC_IO), CONF(CHOWN_RESTRICTED), CONF(FILESIZEBITS), CONF(LINK_MAX), 125 CONF(MAX_CANON), CONF(MAX_INPUT), CONF(NAME_MAX), CONF(NO_TRUNC), 126 CONF(PATH_MAX), CONF(PIPE_BUF), CONF(PRIO_IO), CONF(SYMLINK_MAX), 127 CONF(SYNC_IO), 128 {"_POSIX_VDISABLE", _PC_VDISABLE}, 129}; 130 131// Strings out of a header 132struct config confstrs[] = { 133#undef CONF 134#define CONF(n) {#n,_CS_ ## n} 135 CONF(PATH), CONF(V7_ENV) 136}; 137 138// Integers out of a header 139struct config limits[] = { 140#undef CONF 141#define CONF(n) {#n,n} 142 CONF(_POSIX_AIO_LISTIO_MAX), CONF(_POSIX_AIO_MAX), CONF(_POSIX_ARG_MAX), 143 CONF(_POSIX_CHILD_MAX), CONF(_POSIX_DELAYTIMER_MAX), 144 CONF(_POSIX_HOST_NAME_MAX), CONF(_POSIX_LINK_MAX), 145 CONF(_POSIX_LOGIN_NAME_MAX), CONF(_POSIX_MAX_CANON), 146 CONF(_POSIX_MAX_INPUT), CONF(_POSIX_NAME_MAX), CONF(_POSIX_NGROUPS_MAX), 147 CONF(_POSIX_OPEN_MAX), CONF(_POSIX_PATH_MAX), CONF(_POSIX_PIPE_BUF), 148 CONF(_POSIX_RE_DUP_MAX), CONF(_POSIX_RTSIG_MAX), CONF(_POSIX_SEM_NSEMS_MAX), 149 CONF(_POSIX_SEM_VALUE_MAX), CONF(_POSIX_SIGQUEUE_MAX), CONF(_POSIX_SSIZE_MAX), 150 CONF(_POSIX_STREAM_MAX), CONF(_POSIX_SYMLINK_MAX), CONF(_POSIX_SYMLOOP_MAX), 151 CONF(_POSIX_THREAD_DESTRUCTOR_ITERATIONS), CONF(_POSIX_THREAD_KEYS_MAX), 152 CONF(_POSIX_THREAD_THREADS_MAX), CONF(_POSIX_TIMER_MAX), 153 CONF(_POSIX_TTY_NAME_MAX), CONF(_POSIX_TZNAME_MAX), 154 CONF(CHAR_MAX), CONF(CHAR_MIN), CONF(INT_MAX), CONF(INT_MIN), CONF(SCHAR_MAX), 155 CONF(SCHAR_MIN), CONF(SHRT_MAX), CONF(SHRT_MIN), CONF(SSIZE_MAX), 156 CONF(UCHAR_MAX), CONF(UINT_MAX), CONF(ULONG_MAX), CONF(USHRT_MAX), 157 CONF(CHAR_BIT), 158 /* Not available in glibc without _GNU_SOURCE. */ 159 {"LONG_BIT", 8*sizeof(long)}, 160 {"WORD_BIT", 8*sizeof(int)}, 161#undef CONF 162#define CONF(n) {#n,_ ## n} 163 CONF(POSIX2_BC_BASE_MAX), CONF(POSIX2_BC_DIM_MAX), 164 CONF(POSIX2_BC_SCALE_MAX), CONF(POSIX2_BC_STRING_MAX), 165 CONF(POSIX2_CHARCLASS_NAME_MAX), CONF(POSIX2_COLL_WEIGHTS_MAX), 166 CONF(POSIX2_EXPR_NEST_MAX), CONF(POSIX2_LINE_MAX), CONF(POSIX2_RE_DUP_MAX), 167}; 168 169// Names we need to handle ourselves (default to blank but shouldn't error) 170struct config others[] = { 171 {"LFS_CFLAGS", 0}, {"LFS_LDFLAGS", 0}, {"LFS_LIBS", 0} 172}; 173 174static void show_conf(int i, struct config *c, const char *path) 175{ 176 if (i<2) { 177 long l = i ? pathconf(path, c->value) : sysconf(c->value); 178 179 if (l == -1) puts("undefined"); 180 else printf("%ld\n", l); 181 } else if (i==2) { 182 confstr(c->value, toybuf, sizeof(toybuf)); 183 puts(toybuf); 184 } else if (i==3) printf("%lld\n", c->value); 185 // LFS_CFLAGS on 32 bit should enable Large File Support for kernel builds 186 else puts(sizeof(long)==4 && !strcmp(c->name, "LFS_CFLAGS") ? 187 "-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" : ""); 188} 189 190void getconf_main(void) 191{ 192 struct config *configs[] = {sysconfs, pathconfs, confstrs, limits, others}, 193 *c = NULL; 194 int i, j, lens[] = {ARRAY_LEN(sysconfs), ARRAY_LEN(pathconfs), 195 ARRAY_LEN(confstrs), ARRAY_LEN(limits), ARRAY_LEN(others)}; 196 char *name, *path = (toys.optc==2) ? toys.optargs[1] : "/", 197 *config_names[] = {"sysconf(3)", "pathconf(3)", "confstr(3)", 198 "<limits.h>", "Misc"}; 199 200 if (toys.optflags&FLAG_a) { 201 for (i = 0; i<5; i++) { 202 for (j = 0; j<lens[i]; j++) { 203 c = &configs[i][j]; 204 printf("%-34s ", c->name); 205 show_conf(i, c, path); 206 } 207 } 208 return; 209 } 210 211 if (toys.optflags&FLAG_l) { 212 for (i = 0; i<5; i++) { 213 printf("%s\n", config_names[i]); 214 for (j = 0; j<lens[i]; j++) printf(" %s\n", configs[i][j].name); 215 } 216 return; 217 } 218 219 if (toys.optc<1) help_exit(0); 220 name = *toys.optargs; 221 222 // Workaround for autogen using CS_PATH instead of PATH 223 if (!strcmp("CS_PATH", name)) name += 3; 224 225 // Find the config. 226 for (i = j = 0; ; j++) { 227 if (j==lens[i]) j = 0, i++; 228 if (i==5) error_exit("bad '%s'", name); 229 c = &configs[i][j]; 230 if (!strcmp(c->name, name)) break; 231 } 232 233 // Check that we do/don't have the extra path argument. 234 if (i==1) { 235 if (toys.optc!=2) help_exit("%s needs a path", name); 236 } else if (toys.optc!=1) help_exit("%s does not take a path", name); 237 238 show_conf(i, c, path); 239} 240