1// Copyright 2018 Tobias Klauser. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package sysconf
6
7import "golang.org/x/sys/unix"
8
9// sysconf implements sysconf(3) as in the OpenBSD 6.3 libc.
10func sysconf(name int) (int64, error) {
11	switch name {
12	case SC_AIO_LISTIO_MAX,
13		SC_AIO_MAX,
14		SC_AIO_PRIO_DELTA_MAX:
15		return -1, nil
16	case SC_ARG_MAX:
17		return sysctl32("kern.argmax"), nil
18	case SC_ATEXIT_MAX:
19		return -1, nil
20	case SC_CHILD_MAX:
21		var rlim unix.Rlimit
22		if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlim); err == nil {
23			if rlim.Cur != unix.RLIM_INFINITY {
24				return int64(rlim.Cur), nil
25			}
26		}
27		return -1, nil
28	case SC_CLK_TCK:
29		return _CLK_TCK, nil
30	case SC_DELAYTIMER_MAX:
31		return -1, nil
32	case SC_GETGR_R_SIZE_MAX:
33		return _GR_BUF_LEN, nil
34	case SC_GETPW_R_SIZE_MAX:
35		return _PW_BUF_LEN, nil
36	case SC_IOV_MAX:
37		return _IOV_MAX, nil
38	case SC_LOGIN_NAME_MAX:
39		return _LOGIN_NAME_MAX, nil
40	case SC_NGROUPS_MAX:
41		return sysctl32("kern.ngroups"), nil
42	case SC_OPEN_MAX:
43		var rlim unix.Rlimit
44		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
45			if rlim.Cur != unix.RLIM_INFINITY {
46				return int64(rlim.Cur), nil
47			}
48		}
49		return -1, nil
50	case SC_SEM_NSEMS_MAX:
51		return -1, nil
52	case SC_SEM_VALUE_MAX:
53		return _SEM_VALUE_MAX, nil
54	case SC_SIGQUEUE_MAX:
55		return -1, nil
56	case SC_STREAM_MAX:
57		var rlim unix.Rlimit
58		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
59			if rlim.Cur != unix.RLIM_INFINITY {
60				if rlim.Cur > _SHRT_MAX {
61					return _SHRT_MAX, nil
62				}
63				return int64(rlim.Cur), nil
64			}
65		}
66		return -1, nil
67	case SC_THREAD_DESTRUCTOR_ITERATIONS:
68		return _PTHREAD_DESTRUCTOR_ITERATIONS, nil
69	case SC_THREAD_KEYS_MAX:
70		return _PTHREAD_KEYS_MAX, nil
71	case SC_THREAD_STACK_MIN:
72		return _PTHREAD_STACK_MIN, nil
73	case SC_THREAD_THREADS_MAX:
74		return -1, nil
75	case SC_TIMER_MAX:
76		return -1, nil
77	case SC_TTY_NAME_MAX:
78		return _TTY_NAME_MAX, nil
79	case SC_TZNAME_MAX:
80		return _NAME_MAX, nil
81
82	case SC_BARRIERS:
83		return _POSIX_BARRIERS, nil
84	case SC_FSYNC:
85		return _POSIX_FSYNC, nil
86	case SC_IPV6:
87		if _POSIX_IPV6 == 0 {
88			fd, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0)
89			if err == nil && fd >= 0 {
90				unix.Close(fd)
91				return int64(200112), nil
92			}
93			return 0, nil
94		}
95		return _POSIX_IPV6, nil
96	case SC_JOB_CONTROL:
97		return _POSIX_JOB_CONTROL, nil
98	case SC_MAPPED_FILES:
99		return _POSIX_MAPPED_FILES, nil
100	case SC_MONOTONIC_CLOCK:
101		return _POSIX_MONOTONIC_CLOCK, nil
102	case SC_SAVED_IDS:
103		return _POSIX_SAVED_IDS, nil
104	case SC_SEMAPHORES:
105		return _POSIX_SEMAPHORES, nil
106	case SC_SPAWN:
107		return _POSIX_SPAWN, nil
108	case SC_SPIN_LOCKS:
109		return _POSIX_SPIN_LOCKS, nil
110	case SC_SPORADIC_SERVER:
111		return _POSIX_SPORADIC_SERVER, nil
112	case SC_SYNCHRONIZED_IO:
113		return _POSIX_SYNCHRONIZED_IO, nil
114	case SC_THREAD_ATTR_STACKADDR:
115		return _POSIX_THREAD_ATTR_STACKADDR, nil
116	case SC_THREAD_ATTR_STACKSIZE:
117		return _POSIX_THREAD_ATTR_STACKSIZE, nil
118	case SC_THREAD_CPUTIME:
119		return _POSIX_THREAD_CPUTIME, nil
120	case SC_THREAD_PRIO_INHERIT:
121		return _POSIX_THREAD_PRIO_INHERIT, nil
122	case SC_THREAD_PRIO_PROTECT:
123		return _POSIX_THREAD_PRIO_PROTECT, nil
124	case SC_THREAD_PRIORITY_SCHEDULING:
125		return _POSIX_THREAD_PRIORITY_SCHEDULING, nil
126	case SC_THREAD_PROCESS_SHARED:
127		return _POSIX_THREAD_PROCESS_SHARED, nil
128	case SC_THREAD_ROBUST_PRIO_INHERIT:
129		return _POSIX_THREAD_ROBUST_PRIO_INHERIT, nil
130	case SC_THREAD_ROBUST_PRIO_PROTECT:
131		return _POSIX_THREAD_ROBUST_PRIO_PROTECT, nil
132	case SC_THREAD_SAFE_FUNCTIONS:
133		return _POSIX_THREAD_SAFE_FUNCTIONS, nil
134	case SC_THREAD_SPORADIC_SERVER:
135		return _POSIX_THREAD_SPORADIC_SERVER, nil
136	case SC_THREADS:
137		return _POSIX_THREADS, nil
138	case SC_TIMEOUTS:
139		return _POSIX_TIMEOUTS, nil
140	case SC_TIMERS:
141		return _POSIX_TIMERS, nil
142	case SC_TRACE,
143		SC_TRACE_EVENT_FILTER,
144		SC_TRACE_EVENT_NAME_MAX,
145		SC_TRACE_INHERIT,
146		SC_TRACE_LOG:
147		return _POSIX_TRACE, nil
148	case SC_TYPED_MEMORY_OBJECTS:
149		return _POSIX_TYPED_MEMORY_OBJECTS, nil
150
151	case SC_V7_ILP32_OFF32:
152		return _POSIX_V7_ILP32_OFF32, nil
153	case SC_V7_ILP32_OFFBIG:
154		if _POSIX_V7_ILP32_OFFBIG == 0 {
155			if unix.SizeofInt*_CHAR_BIT == 32 &&
156				unix.SizeofLong*_CHAR_BIT == 32 &&
157				unix.SizeofPtr*_CHAR_BIT == 32 &&
158				sizeofOffT*_CHAR_BIT >= 64 {
159				return 1, nil
160			}
161			return -1, nil
162		}
163		return _POSIX_V7_ILP32_OFFBIG, nil
164	case SC_V7_LP64_OFF64:
165		if _POSIX_V7_LP64_OFF64 == 0 {
166			if unix.SizeofInt*_CHAR_BIT == 32 &&
167				unix.SizeofLong*_CHAR_BIT == 64 &&
168				unix.SizeofPtr*_CHAR_BIT == 64 &&
169				sizeofOffT*_CHAR_BIT == 64 {
170				return 1, nil
171			}
172			return -1, nil
173		}
174		return _POSIX_V7_LP64_OFF64, nil
175	case SC_V7_LPBIG_OFFBIG:
176		if _POSIX_V7_LPBIG_OFFBIG == 0 {
177			if unix.SizeofInt*_CHAR_BIT >= 32 &&
178				unix.SizeofLong*_CHAR_BIT >= 64 &&
179				unix.SizeofPtr*_CHAR_BIT >= 64 &&
180				sizeofOffT*_CHAR_BIT >= 64 {
181				return 1, nil
182			}
183			return -1, nil
184		}
185		return _POSIX_V7_LPBIG_OFFBIG, nil
186
187	case SC_V6_ILP32_OFF32:
188		return _POSIX_V6_ILP32_OFF32, nil
189	case SC_V6_ILP32_OFFBIG:
190		if _POSIX_V6_ILP32_OFFBIG == 0 {
191			if unix.SizeofInt*_CHAR_BIT == 32 &&
192				unix.SizeofLong*_CHAR_BIT == 32 &&
193				unix.SizeofPtr*_CHAR_BIT == 32 &&
194				sizeofOffT*_CHAR_BIT >= 64 {
195				return 1, nil
196			}
197			return -1, nil
198		}
199		return _POSIX_V6_ILP32_OFFBIG, nil
200	case SC_V6_LP64_OFF64:
201		if _POSIX_V6_LP64_OFF64 == 0 {
202			if unix.SizeofInt*_CHAR_BIT == 32 &&
203				unix.SizeofLong*_CHAR_BIT == 64 &&
204				unix.SizeofPtr*_CHAR_BIT == 64 &&
205				sizeofOffT*_CHAR_BIT == 64 {
206				return 1, nil
207			}
208			return -1, nil
209		}
210		return _POSIX_V6_LP64_OFF64, nil
211	case SC_V6_LPBIG_OFFBIG:
212		if _POSIX_V6_LPBIG_OFFBIG == 0 {
213			if unix.SizeofInt*_CHAR_BIT >= 32 &&
214				unix.SizeofLong*_CHAR_BIT >= 64 &&
215				unix.SizeofPtr*_CHAR_BIT >= 64 &&
216				sizeofOffT*_CHAR_BIT >= 64 {
217				return 1, nil
218			}
219			return -1, nil
220		}
221		return _POSIX_V6_LPBIG_OFFBIG, nil
222
223	case SC_2_CHAR_TERM:
224		return _POSIX2_CHAR_TERM, nil
225	case SC_2_PBS,
226		SC_2_PBS_ACCOUNTING,
227		SC_2_PBS_CHECKPOINT,
228		SC_2_PBS_LOCATE,
229		SC_2_PBS_MESSAGE,
230		SC_2_PBS_TRACK:
231		return _POSIX2_PBS, nil
232	case SC_2_UPE:
233		return _POSIX2_UPE, nil
234	case SC_2_VERSION:
235		return _POSIX2_VERSION, nil
236
237	case SC_XOPEN_CRYPT:
238		return _XOPEN_CRYPT, nil
239	case SC_XOPEN_ENH_I18N:
240		return _XOPEN_ENH_I18N, nil
241	case SC_XOPEN_REALTIME:
242		return _XOPEN_REALTIME, nil
243	case SC_XOPEN_REALTIME_THREADS:
244		return _XOPEN_REALTIME_THREADS, nil
245	case SC_XOPEN_SHM:
246		return _XOPEN_SHM, nil
247	case SC_XOPEN_STREAMS:
248		return _XOPEN_STREAMS, nil
249	case SC_XOPEN_UNIX:
250		return _XOPEN_UNIX, nil
251	case SC_XOPEN_UUCP:
252		return _XOPEN_UUCP, nil
253
254	case SC_AVPHYS_PAGES:
255		if uvm, err := unix.SysctlUvmexp("vm.uvmexp"); err == nil {
256			return int64(uvm.Free), nil
257		}
258		return -1, nil
259	case SC_PHYS_PAGES:
260		return sysctl64("hw.physmem") / int64(unix.Getpagesize()), nil
261	case SC_NPROCESSORS_CONF:
262		return sysctl32("hw.ncpu"), nil
263	case SC_NPROCESSORS_ONLN:
264		if val, err := unix.SysctlUint32("hw.ncpuonline"); err == nil {
265			return int64(val), nil
266		}
267		return sysctl32("hw.ncpu"), nil
268	}
269
270	return sysconfGeneric(name)
271}
272