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 (
8	"golang.org/x/sys/unix"
9)
10
11const (
12	_HOST_NAME_MAX  = _MAXHOSTNAMELEN - 1
13	_LOGIN_NAME_MAX = _MAXLOGNAME
14	_SYMLOOP_MAX    = _MAXSYMLINKS
15)
16
17// sysconf implements sysconf(3) as in the Darwin libc, version 1244.30.3
18// (derived from the FreeBSD libc).
19func sysconf(name int) (int64, error) {
20	switch name {
21	case SC_AIO_LISTIO_MAX:
22		fallthrough
23	case SC_AIO_MAX:
24		return sysctl32("kern.aiomax"), nil
25	case SC_AIO_PRIO_DELTA_MAX:
26		return -1, nil
27	case SC_ARG_MAX:
28		return sysctl32("kern.argmax"), nil
29	case SC_ATEXIT_MAX:
30		return _INT_MAX, nil
31	case SC_CHILD_MAX:
32		var rlim unix.Rlimit
33		if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlim); err == nil {
34			if rlim.Cur != unix.RLIM_INFINITY {
35				return int64(rlim.Cur), nil
36			}
37		}
38		return -1, nil
39	case SC_CLK_TCK:
40		return _CLK_TCK, nil
41	case SC_DELAYTIMER_MAX:
42		return -1, nil
43	case SC_GETGR_R_SIZE_MAX:
44		return 4096, nil
45	case SC_GETPW_R_SIZE_MAX:
46		return 4096, nil
47	case SC_IOV_MAX:
48		return _IOV_MAX, nil
49	case SC_MQ_OPEN_MAX:
50		return -1, nil
51	case SC_MQ_PRIO_MAX:
52		return -1, nil
53	case SC_NGROUPS_MAX:
54		return sysctl32("kern.ngroups"), nil
55	case SC_OPEN_MAX, SC_STREAM_MAX:
56		var rlim unix.Rlimit
57		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
58			if rlim.Cur != unix.RLIM_INFINITY {
59				return int64(rlim.Cur), nil
60			}
61		}
62		return -1, nil
63	case SC_RTSIG_MAX:
64		return -1, nil
65	case SC_SEM_NSEMS_MAX:
66		return sysctl32("kern.sysv.semmns"), nil
67	case SC_SEM_VALUE_MAX:
68		return _POSIX_SEM_VALUE_MAX, nil
69	case SC_SIGQUEUE_MAX:
70		return -1, nil
71	case SC_THREAD_DESTRUCTOR_ITERATIONS:
72		return _PTHREAD_DESTRUCTOR_ITERATIONS, nil
73	case SC_THREAD_KEYS_MAX:
74		return _PTHREAD_KEYS_MAX, nil
75	case SC_THREAD_PRIO_INHERIT:
76		return _POSIX_THREAD_PRIO_INHERIT, nil
77	case SC_THREAD_PRIO_PROTECT:
78		return _POSIX_THREAD_PRIO_PROTECT, nil
79	case SC_THREAD_STACK_MIN:
80		return _PTHREAD_STACK_MIN, nil
81	case SC_THREAD_THREADS_MAX:
82		return -1, nil
83	case SC_TIMER_MAX:
84		return -1, nil
85	case SC_TTY_NAME_MAX:
86		// should be _PATH_DEV instead of "/"
87		return pathconf("/", _PC_NAME_MAX), nil
88	case SC_TZNAME_MAX:
89		return pathconf(_PATH_ZONEINFO, _PC_NAME_MAX), nil
90
91	case SC_IPV6:
92		if _POSIX_IPV6 == 0 {
93			fd, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0)
94			if err == nil && fd >= 0 {
95				unix.Close(fd)
96				return int64(200112), nil
97			}
98			return 0, nil
99		}
100		return _POSIX_IPV6, nil
101	case SC_MESSAGE_PASSING:
102		if _POSIX_MESSAGE_PASSING == 0 {
103			return yesno(sysctl32("p1003_1b.message_passing")), nil
104		}
105		return _POSIX_MESSAGE_PASSING, nil
106	case SC_PRIORITIZED_IO:
107		if _POSIX_PRIORITIZED_IO == 0 {
108			return yesno(sysctl32("p1003_1b.prioritized_io")), nil
109		}
110		return _POSIX_PRIORITIZED_IO, nil
111	case SC_PRIORITY_SCHEDULING:
112		if _POSIX_PRIORITY_SCHEDULING == 0 {
113			return yesno(sysctl32("p1003_1b.priority_scheduling")), nil
114		}
115		return _POSIX_PRIORITY_SCHEDULING, nil
116	case SC_REALTIME_SIGNALS:
117		if _POSIX_REALTIME_SIGNALS == 0 {
118			return yesno(sysctl32("p1003_1b.realtime_signals")), nil
119		}
120		return _POSIX_REALTIME_SIGNALS, nil
121	case SC_SAVED_IDS:
122		return yesno(sysctl32("kern.saved_ids")), nil
123	case SC_SEMAPHORES:
124		if _POSIX_SEMAPHORES == 0 {
125			return yesno(sysctl32("p1003_1b.semaphores")), nil
126		}
127		return _POSIX_SEMAPHORES, nil
128	case SC_SPAWN:
129		return _POSIX_SPAWN, nil
130	case SC_SPIN_LOCKS:
131		return _POSIX_SPIN_LOCKS, nil
132	case SC_SPORADIC_SERVER:
133		return _POSIX_SPORADIC_SERVER, nil
134	case SC_SS_REPL_MAX:
135		return _POSIX_SS_REPL_MAX, nil
136	case SC_SYNCHRONIZED_IO:
137		if _POSIX_SYNCHRONIZED_IO == 0 {
138			return yesno(sysctl32("p1003_1b.synchronized_io")), nil
139		}
140		return _POSIX_SYNCHRONIZED_IO, nil
141	case SC_THREAD_ATTR_STACKADDR:
142		return _POSIX_THREAD_ATTR_STACKADDR, nil
143	case SC_THREAD_ATTR_STACKSIZE:
144		return _POSIX_THREAD_ATTR_STACKSIZE, nil
145	case SC_THREAD_CPUTIME:
146		return _POSIX_THREAD_CPUTIME, nil
147	case SC_THREAD_PRIORITY_SCHEDULING:
148		return _POSIX_THREAD_PRIORITY_SCHEDULING, nil
149	case SC_THREAD_PROCESS_SHARED:
150		return _POSIX_THREAD_PROCESS_SHARED, nil
151	case SC_THREAD_SAFE_FUNCTIONS:
152		return _POSIX_THREAD_SAFE_FUNCTIONS, nil
153	case SC_THREAD_SPORADIC_SERVER:
154		return _POSIX_THREAD_SPORADIC_SERVER, nil
155	case SC_TIMERS:
156		if _POSIX_TIMERS == 0 {
157			return yesno(sysctl32("p1003_1b.timers")), nil
158		}
159		return _POSIX_TIMERS, nil
160	case SC_TRACE:
161		return _POSIX_TRACE, nil
162	case SC_TRACE_EVENT_FILTER:
163		return _POSIX_TRACE_EVENT_FILTER, nil
164	case SC_TRACE_EVENT_NAME_MAX:
165		return _POSIX_TRACE_EVENT_NAME_MAX, nil
166	case SC_TRACE_INHERIT:
167		return _POSIX_TRACE_INHERIT, nil
168	case SC_TRACE_LOG:
169		return _POSIX_TRACE_LOG, nil
170	case SC_TRACE_NAME_MAX:
171		return _POSIX_TRACE_NAME_MAX, nil
172	case SC_TRACE_SYS_MAX:
173		return _POSIX_TRACE_SYS_MAX, nil
174	case SC_TRACE_USER_EVENT_MAX:
175		return _POSIX_TRACE_USER_EVENT_MAX, nil
176	case SC_TYPED_MEMORY_OBJECTS:
177		return _POSIX_TYPED_MEMORY_OBJECTS, nil
178	case SC_VERSION:
179		// TODO(tk): darwin libc uses sysctl(CTL_KERN, KERN_POSIX1)
180		return _POSIX_VERSION, nil
181
182	case SC_V6_ILP32_OFF32:
183		if _V6_ILP32_OFF32 == 0 {
184			if unix.SizeofInt*_CHAR_BIT == 32 &&
185				unix.SizeofInt == unix.SizeofLong &&
186				unix.SizeofLong == unix.SizeofPtr &&
187				unix.SizeofPtr == sizeofOffT {
188				return 1, nil
189			}
190			return -1, nil
191		}
192		return _V6_ILP32_OFF32, nil
193	case SC_V6_ILP32_OFFBIG:
194		if _V6_ILP32_OFFBIG == 0 {
195			if unix.SizeofInt*_CHAR_BIT == 32 &&
196				unix.SizeofInt == unix.SizeofLong &&
197				unix.SizeofLong == unix.SizeofPtr &&
198				sizeofOffT*_CHAR_BIT >= 64 {
199				return 1, nil
200			}
201			return -1, nil
202		}
203		return _V6_ILP32_OFFBIG, nil
204	case SC_V6_LP64_OFF64:
205		if _V6_LP64_OFF64 == 0 {
206			if unix.SizeofInt*_CHAR_BIT == 32 &&
207				unix.SizeofLong*_CHAR_BIT == 64 &&
208				unix.SizeofLong == unix.SizeofPtr &&
209				unix.SizeofPtr == sizeofOffT {
210				return 1, nil
211			}
212			return -1, nil
213		}
214		return _V6_LP64_OFF64, nil
215	case SC_V6_LPBIG_OFFBIG:
216		if _V6_LPBIG_OFFBIG == 0 {
217			if unix.SizeofInt*_CHAR_BIT >= 32 &&
218				unix.SizeofLong*_CHAR_BIT >= 64 &&
219				unix.SizeofPtr*_CHAR_BIT >= 64 &&
220				sizeofOffT*_CHAR_BIT >= 64 {
221				return 1, nil
222			}
223			return -1, nil
224		}
225		return _V6_LPBIG_OFFBIG, nil
226
227	case SC_2_CHAR_TERM:
228		return _POSIX2_CHAR_TERM, nil
229	case SC_2_PBS,
230		SC_2_PBS_ACCOUNTING,
231		SC_2_PBS_CHECKPOINT,
232		SC_2_PBS_LOCATE,
233		SC_2_PBS_MESSAGE,
234		SC_2_PBS_TRACK:
235		return _POSIX2_PBS, nil
236	case SC_2_UPE:
237		return _POSIX2_UPE, nil
238
239	case SC_XOPEN_CRYPT:
240		return _XOPEN_CRYPT, nil
241	case SC_XOPEN_ENH_I18N:
242		return _XOPEN_ENH_I18N, nil
243	case SC_XOPEN_REALTIME:
244		return _XOPEN_REALTIME, nil
245	case SC_XOPEN_REALTIME_THREADS:
246		return _XOPEN_REALTIME_THREADS, nil
247	case SC_XOPEN_SHM:
248		return _XOPEN_SHM, nil
249	case SC_XOPEN_STREAMS:
250		return -1, nil
251	case SC_XOPEN_UNIX:
252		return _XOPEN_UNIX, nil
253	case SC_XOPEN_VERSION:
254		return _XOPEN_VERSION, nil
255	case SC_XOPEN_XCU_VERSION:
256		return _XOPEN_XCU_VERSION, nil
257
258	case SC_PHYS_PAGES:
259		return sysctl64("hw.memsize") / int64(unix.Getpagesize()), nil
260	case SC_NPROCESSORS_CONF:
261		fallthrough
262	case SC_NPROCESSORS_ONLN:
263		return sysctl32("hw.ncpu"), nil
264	}
265
266	return sysconfGeneric(name)
267}
268