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
9const (
10	_HOST_NAME_MAX  = _MAXHOSTNAMELEN - 1
11	_LOGIN_NAME_MAX = _MAXLOGNAME
12	_SYMLOOP_MAX    = _MAXSYMLINKS
13)
14
15// sysconf implements sysconf(3) as in the FreeBSD 12 libc.
16func sysconf(name int) (int64, error) {
17	switch name {
18	case SC_AIO_LISTIO_MAX:
19		return sysctl32("p1003_1b.aio_listio_max"), nil
20	case SC_AIO_MAX:
21		return sysctl32("p1003_1b.aio_max"), nil
22	case SC_AIO_PRIO_DELTA_MAX:
23		return sysctl32("p1003_1b.aio_prio_delta_max"), nil
24	case SC_ARG_MAX:
25		return sysctl32("kern.argmax"), nil
26	case SC_ATEXIT_MAX:
27		return _ATEXIT_SIZE, nil
28	case SC_CHILD_MAX:
29		var rlim unix.Rlimit
30		if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlim); err == nil {
31			if rlim.Cur != unix.RLIM_INFINITY {
32				return rlim.Cur, nil
33			}
34		}
35		return -1, nil
36	case SC_CLK_TCK:
37		return _CLK_TCK, nil
38	case SC_DELAYTIMER_MAX:
39		return yesno(sysctl32("p1003_1b.delaytimer_max")), nil
40	case SC_GETGR_R_SIZE_MAX, SC_GETPW_R_SIZE_MAX:
41		return -1, nil
42	case SC_IOV_MAX:
43		return sysctl32("kern.iov_max"), nil
44	case SC_MQ_OPEN_MAX:
45		return sysctl32("kern.mqueue.mq_open_max"), nil
46	case SC_MQ_PRIO_MAX:
47		return sysctl32("kern.mqueue.mq_prio_max"), nil
48	case SC_NGROUPS_MAX:
49		return sysctl32("kern.ngroups"), nil
50	case SC_OPEN_MAX:
51		var rlim unix.Rlimit
52		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
53			if rlim.Cur != unix.RLIM_INFINITY {
54				return rlim.Cur, nil
55			}
56		}
57		return -1, nil
58	case SC_RTSIG_MAX:
59		return yesno(sysctl32("p1003_1b.rtsig_max")), nil
60	case SC_SEM_NSEMS_MAX:
61		return -1, nil
62	case SC_SEM_VALUE_MAX:
63		return -1, nil
64	case SC_SIGQUEUE_MAX:
65		return yesno(sysctl32("p1003_1b.sigqueue_max")), nil
66	case SC_STREAM_MAX:
67		var rlim unix.Rlimit
68		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
69			if rlim.Cur != unix.RLIM_INFINITY {
70				return rlim.Cur, nil
71			}
72		}
73		return -1, nil
74	case SC_THREAD_DESTRUCTOR_ITERATIONS:
75		return _PTHREAD_DESTRUCTOR_ITERATIONS, nil
76	case SC_THREAD_KEYS_MAX:
77		return _PTHREAD_KEYS_MAX, nil
78	case SC_THREAD_PRIO_INHERIT:
79		return _POSIX_THREAD_PRIO_INHERIT, nil
80	case SC_THREAD_PRIO_PROTECT:
81		return _POSIX_THREAD_PRIO_PROTECT, nil
82	case SC_THREAD_STACK_MIN:
83		return _PTHREAD_STACK_MIN, nil
84	case SC_THREAD_THREADS_MAX:
85		return -1, nil
86	case SC_TIMER_MAX:
87		return yesno(sysctl32("p1003_1b.timer_max")), nil
88	case SC_TTY_NAME_MAX:
89		return pathconf(_PATH_DEV, _PC_NAME_MAX), nil
90	case SC_TZNAME_MAX:
91		return pathconf(_PATH_ZONEINFO, _PC_NAME_MAX), nil
92
93	case SC_ASYNCHRONOUS_IO:
94		if _POSIX_ASYNCHRONOUS_IO == 0 {
95			return sysctl64("p1003_1b.asynchronous_io"), nil
96		}
97		return _POSIX_ASYNCHRONOUS_IO, nil
98	case SC_IPV6:
99		if _POSIX_IPV6 == 0 {
100			fd, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0)
101			if err == nil && fd >= 0 {
102				unix.Close(fd)
103				return int64(200112), nil
104			}
105			return 0, nil
106		}
107		return _POSIX_IPV6, nil
108	case SC_MESSAGE_PASSING:
109		if _POSIX_MESSAGE_PASSING == 0 {
110			return yesno(sysctl32("p1003_1b.message_passing")), nil
111		}
112		return _POSIX_MESSAGE_PASSING, nil
113	case SC_PRIORITIZED_IO:
114		if _POSIX_PRIORITIZED_IO == 0 {
115			return yesno(sysctl32("p1003_1b.prioritized_io")), nil
116		}
117		return _POSIX_PRIORITIZED_IO, nil
118	case SC_PRIORITY_SCHEDULING:
119		if _POSIX_PRIORITY_SCHEDULING == 0 {
120			return yesno(sysctl32("p1003_1b.priority_scheduling")), nil
121		}
122		return _POSIX_PRIORITY_SCHEDULING, nil
123	case SC_REALTIME_SIGNALS:
124		if _POSIX_REALTIME_SIGNALS == 0 {
125			return yesno(sysctl32("p1003_1b.realtime_signals")), nil
126		}
127		return _POSIX_REALTIME_SIGNALS, nil
128	case SC_SAVED_IDS:
129		return yesno(sysctl32("kern.saved_ids")), nil
130	case SC_SEMAPHORES:
131		if _POSIX_SEMAPHORES == 0 {
132			return yesno(sysctl32("p1003_1b.semaphores")), nil
133		}
134		return _POSIX_SEMAPHORES, nil
135	case SC_SPAWN:
136		return _POSIX_SPAWN, nil
137	case SC_SPIN_LOCKS:
138		return _POSIX_SPIN_LOCKS, nil
139	case SC_SPORADIC_SERVER:
140		return _POSIX_SPORADIC_SERVER, nil
141	case SC_SYNCHRONIZED_IO:
142		if _POSIX_SYNCHRONIZED_IO == 0 {
143			return yesno(sysctl32("p1003_1b.synchronized_io")), nil
144		}
145		return _POSIX_SYNCHRONIZED_IO, nil
146	case SC_THREAD_ATTR_STACKADDR:
147		return _POSIX_THREAD_ATTR_STACKADDR, nil
148	case SC_THREAD_ATTR_STACKSIZE:
149		return _POSIX_THREAD_ATTR_STACKSIZE, nil
150	case SC_THREAD_CPUTIME:
151		return _POSIX_THREAD_CPUTIME, nil
152	case SC_THREAD_PRIORITY_SCHEDULING:
153		return _POSIX_THREAD_PRIORITY_SCHEDULING, nil
154	case SC_THREAD_PROCESS_SHARED:
155		return _POSIX_THREAD_PROCESS_SHARED, nil
156	case SC_THREAD_SAFE_FUNCTIONS:
157		return _POSIX_THREAD_SAFE_FUNCTIONS, nil
158	case SC_THREAD_SPORADIC_SERVER:
159		return _POSIX_THREAD_SPORADIC_SERVER, nil
160	case SC_TIMERS:
161		if _POSIX_TIMERS == 0 {
162			return yesno(sysctl32("p1003_1b.timers")), nil
163		}
164		return _POSIX_TIMERS, nil
165	case SC_TRACE:
166		return _POSIX_TRACE, nil
167	case SC_TYPED_MEMORY_OBJECTS:
168		return _POSIX_TYPED_MEMORY_OBJECTS, nil
169	case SC_VERSION:
170		// TODO(tk): FreeBSD libc uses sysctl(CTL_KERN, KERN_POSIX1)
171		return _POSIX_VERSION, nil
172
173		/* TODO(tk): these need GOARCH-dependent integer size checks
174		case SC_V6_ILP32_OFF32:
175			return _V6_ILP32_OFF32, nil
176		case SC_V6_ILP32_OFFBIG:
177			return _V6_ILP32_OFFBIG, nil
178		case SC_V6_LP64_OFF64:
179			return _V6_LP64_OFF64, nil
180		case SC_V6_LPBIG_OFFBIG:
181			return _V6_LPBIG_OFFBIG, nil
182		*/
183
184	case SC_2_CHAR_TERM:
185		return _POSIX2_CHAR_TERM, nil
186	case SC_2_PBS,
187		SC_2_PBS_ACCOUNTING,
188		SC_2_PBS_CHECKPOINT,
189		SC_2_PBS_LOCATE,
190		SC_2_PBS_MESSAGE,
191		SC_2_PBS_TRACK:
192		return _POSIX2_PBS, nil
193	case SC_2_UPE:
194		return _POSIX2_UPE, nil
195
196	case SC_XOPEN_CRYPT:
197		return _XOPEN_CRYPT, nil
198	case SC_XOPEN_ENH_I18N:
199		return _XOPEN_ENH_I18N, nil
200	case SC_XOPEN_REALTIME:
201		return _XOPEN_REALTIME, nil
202	case SC_XOPEN_REALTIME_THREADS:
203		return _XOPEN_REALTIME_THREADS, nil
204	case SC_XOPEN_SHM:
205		return _XOPEN_SHM, nil
206	case SC_XOPEN_STREAMS:
207		return -1, nil
208	case SC_XOPEN_UNIX:
209		return _XOPEN_UNIX, nil
210
211	case SC_PHYS_PAGES:
212		return sysctl64("hw.availpages"), nil
213	case SC_NPROCESSORS_CONF:
214		fallthrough
215	case SC_NPROCESSORS_ONLN:
216		return sysctl32("hw.ncpu"), nil
217	}
218
219	return sysconfGeneric(name)
220}
221