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