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 
11 USE_GETCONF(NEWTOY(getconf, ">2al", TOYFLAG_USR|TOYFLAG_BIN))
12 
13 config 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 
49 struct 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
58 struct 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
121 struct 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
132 struct 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
139 struct 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)
170 struct config others[] = {
171   {"LFS_CFLAGS", 0}, {"LFS_LDFLAGS", 0}, {"LFS_LIBS", 0}
172 };
173 
show_conf(int i,struct config * c,const char * path)174 static 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 
getconf_main(void)190 void 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