1/*
2 * Copyright 2002-2007, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <unistd.h>
8
9#include <errno.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/resource.h>
14#include <sys/statvfs.h>
15
16#include <SupportDefs.h>
17
18#include <directories.h>
19#include <fs_info.h>
20#include <posix/realtime_sem_defs.h>
21#include <signal_defs.h>
22#include <symbol_versioning.h>
23#include <syscalls.h>
24#include <thread_defs.h>
25#include <user_group.h>
26#include <user_timer_defs.h>
27
28#include <errno_private.h>
29#include <libroot_private.h>
30#include <time_private.h>
31#include <unistd_private.h>
32
33
34int
35getdtablesize(void)
36{
37	struct rlimit rlimit;
38	if (getrlimit(RLIMIT_NOFILE, &rlimit) < 0)
39		return 0;
40
41	return rlimit.rlim_cur;
42}
43
44
45long
46__sysconf_beos(int name)
47{
48	switch (name) {
49		case _SC_CLK_TCK:
50			return CLK_TCK_BEOS;
51	}
52
53	return __sysconf(name);
54}
55
56
57long
58__sysconf(int name)
59{
60	int err;
61	// TODO: This is about what BeOS does, better POSIX conformance would be
62	// nice, though
63
64	switch (name) {
65		case _SC_ARG_MAX:
66			return ARG_MAX;
67		case _SC_CHILD_MAX:
68			return CHILD_MAX;
69		case _SC_CLK_TCK:
70			return CLK_TCK;
71		case _SC_JOB_CONTROL:
72			return 1;
73		case _SC_NGROUPS_MAX:
74			return NGROUPS_MAX;
75		case _SC_OPEN_MAX:
76			return OPEN_MAX;
77		case _SC_SAVED_IDS:
78			return 1;
79		case _SC_STREAM_MAX:
80			return STREAM_MAX;
81		case _SC_TZNAME_MAX:
82			return TZNAME_MAX;
83		case _SC_VERSION:
84			return _POSIX_VERSION;
85		case _SC_GETGR_R_SIZE_MAX:
86			return MAX_GROUP_BUFFER_SIZE;
87		case _SC_GETPW_R_SIZE_MAX:
88			return MAX_PASSWD_BUFFER_SIZE;
89		case _SC_PAGE_SIZE:
90			return B_PAGE_SIZE;
91		case _SC_SEM_NSEMS_MAX:
92			return MAX_POSIX_SEMS;
93		case _SC_SEM_VALUE_MAX:
94			return _POSIX_SEM_VALUE_MAX;
95		case _SC_SEMAPHORES:
96			return _POSIX_SEMAPHORES;
97		case _SC_THREADS:
98			return _POSIX_THREADS;
99		case _SC_IOV_MAX:
100			return IOV_MAX;
101		case _SC_NPROCESSORS_MAX:
102			return B_MAX_CPU_COUNT;
103		case _SC_NPROCESSORS_CONF:
104		{
105			system_info info;
106			err = get_system_info(&info);
107			if (err < B_OK) {
108				__set_errno(err);
109				return -1;
110			}
111			return info.cpu_count;
112		}
113		case _SC_NPROCESSORS_ONLN:
114		{
115			system_info info;
116			int i;
117			int count = 0;
118			err = get_system_info(&info);
119			if (err < B_OK) {
120				__set_errno(err);
121				return -1;
122			}
123			for (i = 0; i < info.cpu_count; i++)
124				if (_kern_cpu_enabled(i))
125					count++;
126			return count;
127		}
128		case _SC_CPUID_MAX:
129			return B_MAX_CPU_COUNT - 1;
130		case _SC_ATEXIT_MAX:
131			return ATEXIT_MAX;
132		case _SC_PASS_MAX:
133			break;
134			//XXX:return PASS_MAX;
135		case _SC_PHYS_PAGES:
136		{
137			system_info info;
138			err = get_system_info(&info);
139			if (err < B_OK) {
140				__set_errno(err);
141				return -1;
142			}
143			return info.max_pages;
144		}
145		case _SC_AVPHYS_PAGES:
146		{
147			system_info info;
148			err = get_system_info(&info);
149			if (err < B_OK) {
150				__set_errno(err);
151				return -1;
152			}
153			return info.max_pages - info.used_pages;
154		}
155		case _SC_MAPPED_FILES:
156			return _POSIX_MAPPED_FILES;
157		case _SC_THREAD_PROCESS_SHARED:
158			return _POSIX_THREAD_PROCESS_SHARED;
159		case _SC_THREAD_STACK_MIN:
160			return MIN_USER_STACK_SIZE;
161		case _SC_THREAD_ATTR_STACKADDR:
162			return _POSIX_THREAD_ATTR_STACKADDR;
163		case _SC_THREAD_ATTR_STACKSIZE:
164			return _POSIX_THREAD_ATTR_STACKSIZE;
165		case _SC_THREAD_PRIORITY_SCHEDULING:
166			return _POSIX_THREAD_PRIORITY_SCHEDULING;
167		case _SC_REALTIME_SIGNALS:
168			return _POSIX_REALTIME_SIGNALS;
169		case _SC_MEMORY_PROTECTION:
170			return _POSIX_MEMORY_PROTECTION;
171		case _SC_SIGQUEUE_MAX:
172			return MAX_QUEUED_SIGNALS;
173		case _SC_RTSIG_MAX:
174			return SIGRTMAX - SIGRTMIN + 1;
175		case _SC_MONOTONIC_CLOCK:
176			return _POSIX_MONOTONIC_CLOCK;
177		case _SC_DELAYTIMER_MAX:
178			return MAX_USER_TIMER_OVERRUN_COUNT;
179		case _SC_TIMER_MAX:
180			return MAX_USER_TIMERS_PER_TEAM;
181		case _SC_TIMERS:
182			return _POSIX_TIMERS;
183		case _SC_CPUTIME:
184			return _POSIX_CPUTIME;
185		case _SC_THREAD_CPUTIME:
186			return _POSIX_THREAD_CPUTIME;
187
188		// not POSIX (anymore)
189		case _SC_PIPE:
190		case _SC_SELECT:
191		case _SC_POLL:
192			return 1;
193	}
194
195	__set_errno(EINVAL);
196	return -1;
197}
198
199
200enum {
201	FS_BFS,
202	FS_FAT,
203	FS_EXT,
204	FS_UNKNOWN
205};
206
207
208static int
209fstype(const char *fsh_name)
210{
211	if (!strncmp(fsh_name, "bfs", B_OS_NAME_LENGTH))
212		return FS_BFS;
213	if (!strncmp(fsh_name, "dos", B_OS_NAME_LENGTH))
214		return FS_FAT;
215	if (!strncmp(fsh_name, "fat", B_OS_NAME_LENGTH))
216		return FS_FAT;
217	if (!strncmp(fsh_name, "ext2", B_OS_NAME_LENGTH))
218		return FS_EXT;
219	if (!strncmp(fsh_name, "ext3", B_OS_NAME_LENGTH))
220		return FS_EXT;
221	return FS_UNKNOWN;
222}
223
224
225
226static long
227__pathconf_common(struct statvfs *fs, struct stat *st,
228	int name)
229{
230	fs_info info;
231	int ret;
232	ret = fs_stat_dev(fs->f_fsid, &info);
233	if (ret < 0) {
234		__set_errno(ret);
235		return -1;
236	}
237
238	// TODO: many cases should check for file type from st.
239	switch (name) {
240		case _PC_CHOWN_RESTRICTED:
241			return _POSIX_CHOWN_RESTRICTED;
242
243		case _PC_MAX_CANON:
244			return MAX_CANON;
245
246		case _PC_MAX_INPUT:
247			return MAX_INPUT;
248
249		case _PC_NAME_MAX:
250			return fs->f_namemax;
251			//return NAME_MAX;
252
253		case _PC_NO_TRUNC:
254			return _POSIX_NO_TRUNC;
255
256		case _PC_PATH_MAX:
257			return PATH_MAX;
258
259		case _PC_PIPE_BUF:
260			return 4096;
261
262		case _PC_LINK_MAX:
263			return LINK_MAX;
264
265		case _PC_VDISABLE:
266			return _POSIX_VDISABLE;
267
268		case _PC_FILESIZEBITS:
269		{
270			int type = fstype(info.fsh_name);
271			switch (type) {
272				case FS_BFS:
273				case FS_EXT:
274					return 64;
275				case FS_FAT:
276					return 32;
277			}
278			// XXX: add fs ? add to statvfs/fs_info ?
279			return FILESIZEBITS;
280		}
281
282		case _PC_SYMLINK_MAX:
283			return SYMLINK_MAX;
284
285		case _PC_2_SYMLINKS:
286		{
287			int type = fstype(info.fsh_name);
288			switch (type) {
289				case FS_BFS:
290				case FS_EXT:
291					return 1;
292				case FS_FAT:
293					return 0;
294			}
295			// XXX: there should be an HAS_SYMLINKS flag
296			// to fs_info...
297			return 1;
298		}
299
300		case _PC_XATTR_EXISTS:
301		case _PC_XATTR_ENABLED:
302		{
303#if 0
304			/* those seem to be Solaris specific,
305			 * else we should return 1 I suppose.
306			 * we don't yet map POSIX xattrs
307			 * to BFS ones anyway.
308			 */
309			if (info.flags & B_FS_HAS_ATTR)
310				return 1;
311			return -1;
312#endif
313			__set_errno(EINVAL);
314			return -1;
315		}
316
317		case _PC_SYNC_IO:
318		case _PC_ASYNC_IO:
319		case _PC_PRIO_IO:
320		case _PC_SOCK_MAXBUF:
321		case _PC_REC_INCR_XFER_SIZE:
322		case _PC_REC_MAX_XFER_SIZE:
323		case _PC_REC_MIN_XFER_SIZE:
324		case _PC_REC_XFER_ALIGN:
325		case _PC_ALLOC_SIZE_MIN:
326			/* not yet supported */
327			__set_errno(EINVAL);
328			return -1;
329
330	}
331
332	__set_errno(EINVAL);
333	return -1;
334}
335
336
337long
338fpathconf(int fd, int name)
339{
340	struct statvfs fs;
341	struct stat st;
342	int ret;
343	if (fd < 0) {
344		__set_errno(EBADF);
345		return -1;
346	}
347	ret = fstat(fd, &st);
348	if (ret < 0)
349		return ret;
350	ret = fstatvfs(fd, &fs);
351	if (ret < 0)
352		return ret;
353	return __pathconf_common(&fs, &st, name);
354}
355
356
357long
358pathconf(const char *path, int name)
359{
360	struct statvfs fs;
361	struct stat st;
362	int ret;
363	if (path == NULL) {
364		__set_errno(EFAULT);
365		return -1;
366	}
367	ret = lstat(path, &st);
368	if (ret < 0)
369		return ret;
370	ret = statvfs(path, &fs);
371	if (ret < 0)
372		return ret;
373	return __pathconf_common(&fs, &st, name);
374}
375
376
377size_t
378confstr(int name, char *buffer, size_t length)
379{
380	size_t stringLength = 0;
381	char *string = "";
382
383	if (!length || !buffer) {
384		__set_errno(EINVAL);
385		return 0;
386	}
387
388	switch (name) {
389		case _CS_PATH:
390			string = kGlobalBinDirectory ":" kSystemAppsDirectory ":"
391				kCommonBinDirectory ":" kCommonDevelopToolsBinDirectory;
392			break;
393		default:
394			__set_errno(EINVAL);
395			return 0;
396	}
397
398	if (buffer != NULL) {
399		stringLength = strlen(string) + 1;
400		strlcpy(buffer, string,
401			min_c(length - 1, stringLength));
402	}
403
404	return stringLength;
405}
406
407
408DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__sysconf_beos", "sysconf@", "BASE");
409
410DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__sysconf", "sysconf@@", "1_ALPHA4");
411