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