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