xref: /PHP-8.2/ext/posix/posix.c (revision f9cfd40f)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Kristian Koehntopp <kris@koehntopp.de>                       |
14    +----------------------------------------------------------------------+
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include <unistd.h>
23 #include "ext/standard/info.h"
24 #include "ext/standard/php_string.h"
25 #include "php_posix.h"
26 
27 #ifdef HAVE_POSIX
28 
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32 
33 #include <sys/resource.h>
34 #include <sys/utsname.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <signal.h>
38 #include <sys/times.h>
39 #include <errno.h>
40 #include <grp.h>
41 #include <pwd.h>
42 #ifdef HAVE_SYS_MKDEV_H
43 # include <sys/mkdev.h>
44 #endif
45 #ifdef HAVE_SYS_SYSMACROS_H
46 # include <sys/sysmacros.h>
47 #endif
48 
49 #include "posix_arginfo.h"
50 
51 ZEND_DECLARE_MODULE_GLOBALS(posix)
52 static PHP_MINFO_FUNCTION(posix);
53 
54 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(posix)55 static PHP_MINFO_FUNCTION(posix)
56 {
57 	php_info_print_table_start();
58 	php_info_print_table_row(2, "POSIX support", "enabled");
59 	php_info_print_table_end();
60 }
61 /* }}} */
62 
PHP_GINIT_FUNCTION(posix)63 static PHP_GINIT_FUNCTION(posix) /* {{{ */
64 {
65 #if defined(COMPILE_DL_POSIX) && defined(ZTS)
66 	ZEND_TSRMLS_CACHE_UPDATE();
67 #endif
68 	posix_globals->last_error = 0;
69 }
70 /* }}} */
71 
72 /* {{{ PHP_MINIT_FUNCTION(posix) */
PHP_MINIT_FUNCTION(posix)73 static PHP_MINIT_FUNCTION(posix)
74 {
75 	register_posix_symbols(module_number);
76 
77 	return SUCCESS;
78 }
79 /* }}} */
80 
81 /* {{{ posix_module_entry */
82 zend_module_entry posix_module_entry = {
83 	STANDARD_MODULE_HEADER,
84 	"posix",
85 	ext_functions,
86 	PHP_MINIT(posix),
87 	NULL,
88 	NULL,
89 	NULL,
90 	PHP_MINFO(posix),
91 	PHP_POSIX_VERSION,
92 	PHP_MODULE_GLOBALS(posix),
93 	PHP_GINIT(posix),
94 	NULL,
95 	NULL,
96 	STANDARD_MODULE_PROPERTIES_EX
97 };
98 /* }}} */
99 
100 #ifdef COMPILE_DL_POSIX
101 #ifdef ZTS
102 ZEND_TSRMLS_CACHE_DEFINE()
103 #endif
ZEND_GET_MODULE(posix)104 ZEND_GET_MODULE(posix)
105 #endif
106 
107 #define PHP_POSIX_RETURN_LONG_FUNC(func_name)	\
108 	ZEND_PARSE_PARAMETERS_NONE();	\
109 	RETURN_LONG(func_name());
110 
111 #define PHP_POSIX_SINGLE_ARG_FUNC(func_name)	\
112 	zend_long val;	\
113 	ZEND_PARSE_PARAMETERS_START(1, 1) \
114 		Z_PARAM_LONG(val) \
115 	ZEND_PARSE_PARAMETERS_END(); \
116 	if (func_name(val) < 0) {	\
117 		POSIX_G(last_error) = errno;	\
118 		RETURN_FALSE;	\
119 	}	\
120 	RETURN_TRUE;
121 
122 /* {{{ Send a signal to a process (POSIX.1, 3.3.2) */
123 
124 PHP_FUNCTION(posix_kill)
125 {
126 	zend_long pid, sig;
127 
128 	ZEND_PARSE_PARAMETERS_START(2, 2)
129 		Z_PARAM_LONG(pid)
130 		Z_PARAM_LONG(sig)
131 	ZEND_PARSE_PARAMETERS_END();
132 
133 	if (kill(pid, sig) < 0) {
134 		POSIX_G(last_error) = errno;
135 		RETURN_FALSE;
136 	}
137 
138 	RETURN_TRUE;
139 }
140 /* }}} */
141 
142 /* {{{ Get the current process id (POSIX.1, 4.1.1) */
PHP_FUNCTION(posix_getpid)143 PHP_FUNCTION(posix_getpid)
144 {
145 	PHP_POSIX_RETURN_LONG_FUNC(getpid);
146 }
147 /* }}} */
148 
149 /* {{{ Get the parent process id (POSIX.1, 4.1.1) */
PHP_FUNCTION(posix_getppid)150 PHP_FUNCTION(posix_getppid)
151 {
152 	PHP_POSIX_RETURN_LONG_FUNC(getppid);
153 }
154 /* }}} */
155 
156 /* {{{ Get the current user id (POSIX.1, 4.2.1) */
PHP_FUNCTION(posix_getuid)157 PHP_FUNCTION(posix_getuid)
158 {
159 	PHP_POSIX_RETURN_LONG_FUNC(getuid);
160 }
161 /* }}} */
162 
163 /* {{{ Get the current group id (POSIX.1, 4.2.1) */
PHP_FUNCTION(posix_getgid)164 PHP_FUNCTION(posix_getgid)
165 {
166 	PHP_POSIX_RETURN_LONG_FUNC(getgid);
167 }
168 /* }}} */
169 
170 /* {{{ Get the current effective user id (POSIX.1, 4.2.1) */
PHP_FUNCTION(posix_geteuid)171 PHP_FUNCTION(posix_geteuid)
172 {
173 	PHP_POSIX_RETURN_LONG_FUNC(geteuid);
174 }
175 /* }}} */
176 
177 /* {{{ Get the current effective group id (POSIX.1, 4.2.1) */
PHP_FUNCTION(posix_getegid)178 PHP_FUNCTION(posix_getegid)
179 {
180 	PHP_POSIX_RETURN_LONG_FUNC(getegid);
181 }
182 /* }}} */
183 
184 /* {{{ Set user id (POSIX.1, 4.2.2) */
PHP_FUNCTION(posix_setuid)185 PHP_FUNCTION(posix_setuid)
186 {
187 	PHP_POSIX_SINGLE_ARG_FUNC(setuid);
188 }
189 /* }}} */
190 
191 /* {{{ Set group id (POSIX.1, 4.2.2) */
PHP_FUNCTION(posix_setgid)192 PHP_FUNCTION(posix_setgid)
193 {
194 	PHP_POSIX_SINGLE_ARG_FUNC(setgid);
195 }
196 /* }}} */
197 
198 /* {{{ Set effective user id */
199 #ifdef HAVE_SETEUID
PHP_FUNCTION(posix_seteuid)200 PHP_FUNCTION(posix_seteuid)
201 {
202 	PHP_POSIX_SINGLE_ARG_FUNC(seteuid);
203 }
204 #endif
205 /* }}} */
206 
207 /* {{{ Set effective group id */
208 #ifdef HAVE_SETEGID
PHP_FUNCTION(posix_setegid)209 PHP_FUNCTION(posix_setegid)
210 {
211 	PHP_POSIX_SINGLE_ARG_FUNC(setegid);
212 }
213 #endif
214 /* }}} */
215 
216 /* {{{ Get supplementary group id's (POSIX.1, 4.2.3) */
217 #ifdef HAVE_GETGROUPS
PHP_FUNCTION(posix_getgroups)218 PHP_FUNCTION(posix_getgroups)
219 {
220 	gid_t *gidlist;
221 	int    result;
222 	int    i;
223 
224 	ZEND_PARSE_PARAMETERS_NONE();
225 
226 	/* MacOS may return more than NGROUPS_MAX groups.
227 	 * Fetch the actual number of groups and create an appropriate allocation. */
228 	if ((result = getgroups(0, NULL)) < 0) {
229 		POSIX_G(last_error) = errno;
230 		RETURN_FALSE;
231 	}
232 
233 	gidlist = emalloc(sizeof(gid_t) * result);
234 	if ((result = getgroups(result, gidlist)) < 0) {
235 		POSIX_G(last_error) = errno;
236 		efree(gidlist);
237 		RETURN_FALSE;
238 	}
239 
240 	array_init(return_value);
241 
242 	for (i=0; i<result; i++) {
243 		add_next_index_long(return_value, gidlist[i]);
244 	}
245 	efree(gidlist);
246 }
247 #endif
248 /* }}} */
249 
250 /* {{{ Get user name (POSIX.1, 4.2.4) */
251 #ifdef HAVE_GETLOGIN
PHP_FUNCTION(posix_getlogin)252 PHP_FUNCTION(posix_getlogin)
253 {
254 	char *p;
255 
256 	ZEND_PARSE_PARAMETERS_NONE();
257 
258 	if (NULL == (p = getlogin())) {
259 		POSIX_G(last_error) = errno;
260 		RETURN_FALSE;
261 	}
262 
263 	RETURN_STRING(p);
264 }
265 #endif
266 /* }}} */
267 
268 /* {{{ Get current process group id (POSIX.1, 4.3.1) */
PHP_FUNCTION(posix_getpgrp)269 PHP_FUNCTION(posix_getpgrp)
270 {
271 	PHP_POSIX_RETURN_LONG_FUNC(getpgrp);
272 }
273 /* }}} */
274 
275 /* {{{ Create session and set process group id (POSIX.1, 4.3.2) */
276 #ifdef HAVE_SETSID
PHP_FUNCTION(posix_setsid)277 PHP_FUNCTION(posix_setsid)
278 {
279 	PHP_POSIX_RETURN_LONG_FUNC(setsid);
280 }
281 #endif
282 /* }}} */
283 
284 /* {{{ Set process group id for job control (POSIX.1, 4.3.3) */
PHP_FUNCTION(posix_setpgid)285 PHP_FUNCTION(posix_setpgid)
286 {
287 	zend_long pid, pgid;
288 
289 	ZEND_PARSE_PARAMETERS_START(2, 2)
290 		Z_PARAM_LONG(pid)
291 		Z_PARAM_LONG(pgid)
292 	ZEND_PARSE_PARAMETERS_END();
293 
294 	if (setpgid(pid, pgid) < 0) {
295 		POSIX_G(last_error) = errno;
296 		RETURN_FALSE;
297 	}
298 
299 	RETURN_TRUE;
300 }
301 /* }}} */
302 
303 /* {{{ Get the process group id of the specified process (This is not a POSIX function, but a SVR4ism, so we compile conditionally) */
304 #ifdef HAVE_GETPGID
PHP_FUNCTION(posix_getpgid)305 PHP_FUNCTION(posix_getpgid)
306 {
307 	zend_long val;
308 
309 	ZEND_PARSE_PARAMETERS_START(1, 1)
310 		Z_PARAM_LONG(val)
311 	ZEND_PARSE_PARAMETERS_END();
312 
313 	if ((val = getpgid(val)) < 0) {
314 		POSIX_G(last_error) = errno;
315 		RETURN_FALSE;
316 	}
317 	RETURN_LONG(val);
318 }
319 #endif
320 /* }}} */
321 
322 /* {{{ Get process group id of session leader (This is not a POSIX function, but a SVR4ism, so be compile conditionally) */
323 #ifdef HAVE_GETSID
PHP_FUNCTION(posix_getsid)324 PHP_FUNCTION(posix_getsid)
325 {
326 	zend_long val;
327 
328 	ZEND_PARSE_PARAMETERS_START(1, 1)
329 		Z_PARAM_LONG(val)
330 	ZEND_PARSE_PARAMETERS_END();
331 
332 	if ((val = getsid(val)) < 0) {
333 		POSIX_G(last_error) = errno;
334 		RETURN_FALSE;
335 	}
336 	RETURN_LONG(val);
337 }
338 #endif
339 /* }}} */
340 
341 /* {{{ Get system name (POSIX.1, 4.4.1) */
PHP_FUNCTION(posix_uname)342 PHP_FUNCTION(posix_uname)
343 {
344 	struct utsname u;
345 
346 	ZEND_PARSE_PARAMETERS_NONE();
347 
348 	if (uname(&u) < 0) {
349 		POSIX_G(last_error) = errno;
350 		RETURN_FALSE;
351 	}
352 
353 	array_init(return_value);
354 
355 	add_assoc_string(return_value, "sysname",  u.sysname);
356 	add_assoc_string(return_value, "nodename", u.nodename);
357 	add_assoc_string(return_value, "release",  u.release);
358 	add_assoc_string(return_value, "version",  u.version);
359 	add_assoc_string(return_value, "machine",  u.machine);
360 
361 #if defined(_GNU_SOURCE) && defined(HAVE_STRUCT_UTSNAME_DOMAINNAME)
362 	add_assoc_string(return_value, "domainname", u.domainname);
363 #endif
364 }
365 /* }}} */
366 
367 /* POSIX.1, 4.5.1 time() - Get System Time
368 							already covered by PHP
369  */
370 
371 /* {{{ Get process times (POSIX.1, 4.5.2) */
PHP_FUNCTION(posix_times)372 PHP_FUNCTION(posix_times)
373 {
374 	struct tms t;
375 	clock_t    ticks;
376 
377 	ZEND_PARSE_PARAMETERS_NONE();
378 
379 	if ((ticks = times(&t)) == -1) {
380 		POSIX_G(last_error) = errno;
381 		RETURN_FALSE;
382 	}
383 
384 	array_init(return_value);
385 
386 	add_assoc_long(return_value, "ticks",	ticks);			/* clock ticks */
387 	add_assoc_long(return_value, "utime",	t.tms_utime);	/* user time */
388 	add_assoc_long(return_value, "stime",	t.tms_stime);	/* system time */
389 	add_assoc_long(return_value, "cutime",	t.tms_cutime);	/* user time of children */
390 	add_assoc_long(return_value, "cstime",	t.tms_cstime);	/* system time of children */
391 }
392 /* }}} */
393 
394 /* POSIX.1, 4.6.1 getenv() - Environment Access
395 							already covered by PHP
396 */
397 
398 /* {{{ Generate terminal path name (POSIX.1, 4.7.1) */
399 #ifdef HAVE_CTERMID
PHP_FUNCTION(posix_ctermid)400 PHP_FUNCTION(posix_ctermid)
401 {
402 	char  buffer[L_ctermid];
403 
404 	ZEND_PARSE_PARAMETERS_NONE();
405 
406 	if (NULL == ctermid(buffer)) {
407 		/* Found no documentation how the defined behaviour is when this
408 		 * function fails
409 		 */
410 		POSIX_G(last_error) = errno;
411 		RETURN_FALSE;
412 	}
413 
414 	RETURN_STRING(buffer);
415 }
416 #endif
417 /* }}} */
418 
419 /* Checks if the provides resource is a stream and if it provides a file descriptor */
php_posix_stream_get_fd(zval * zfp,zend_long * fd)420 static int php_posix_stream_get_fd(zval *zfp, zend_long *fd) /* {{{ */
421 {
422 	php_stream *stream;
423 
424 	php_stream_from_zval_no_verify(stream, zfp);
425 
426 	if (stream == NULL) {
427 		return 0;
428 	}
429 
430 	/* get the fd.
431 	 * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting.
432 	 * It is only used here so that the buffered data warning is not displayed.
433 	 */
434 	if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
435 		php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)fd, 0);
436 	} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
437 		php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)fd, 0);
438 	} else {
439 		php_error_docref(NULL, E_WARNING, "Could not use stream of type '%s'",
440 				stream->ops->label);
441 		return 0;
442 	}
443 	return 1;
444 }
445 /* }}} */
446 
447 /* {{{ Determine terminal device name (POSIX.1, 4.7.2) */
PHP_FUNCTION(posix_ttyname)448 PHP_FUNCTION(posix_ttyname)
449 {
450 	zval *z_fd;
451 	char *p;
452 	zend_long fd = 0;
453 #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
454 	zend_long buflen;
455 #endif
456 
457 	ZEND_PARSE_PARAMETERS_START(1, 1)
458 		Z_PARAM_ZVAL(z_fd)
459 	ZEND_PARSE_PARAMETERS_END();
460 
461 	if (Z_TYPE_P(z_fd) == IS_RESOURCE) {
462 		if (!php_posix_stream_get_fd(z_fd, &fd)) {
463 			RETURN_FALSE;
464 		}
465 	} else {
466 		if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) {
467 			php_error_docref(NULL, E_WARNING, "Argument #1 ($file_descriptor) must be of type int|resource, %s given",
468 				zend_zval_value_name(z_fd));
469 			fd = zval_get_long(z_fd);
470 		}
471 		/* fd must fit in an int and be positive */
472 		if (fd < 0 || fd > INT_MAX) {
473 			php_error_docref(NULL, E_WARNING, "Argument #1 ($file_descriptor) must be between 0 and %d", INT_MAX);
474 			RETURN_FALSE;
475 		}
476 	}
477 #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
478 	buflen = sysconf(_SC_TTY_NAME_MAX);
479 	if (buflen < 1) {
480 		RETURN_FALSE;
481 	}
482 	p = emalloc(buflen);
483 
484 	if (ttyname_r(fd, p, buflen)) {
485 		POSIX_G(last_error) = errno;
486 		efree(p);
487 		RETURN_FALSE;
488 	}
489 	RETVAL_STRING(p);
490 	efree(p);
491 #else
492 	if (NULL == (p = ttyname(fd))) {
493 		POSIX_G(last_error) = errno;
494 		RETURN_FALSE;
495 	}
496 	RETURN_STRING(p);
497 #endif
498 }
499 /* }}} */
500 
501 /* {{{ Determine if filedesc is a tty (POSIX.1, 4.7.1) */
PHP_FUNCTION(posix_isatty)502 PHP_FUNCTION(posix_isatty)
503 {
504 	zval *z_fd;
505 	zend_long fd = 0;
506 
507 	ZEND_PARSE_PARAMETERS_START(1, 1)
508 		Z_PARAM_ZVAL(z_fd)
509 	ZEND_PARSE_PARAMETERS_END();
510 
511 	if (Z_TYPE_P(z_fd) == IS_RESOURCE) {
512 		if (!php_posix_stream_get_fd(z_fd, &fd)) {
513 			RETURN_FALSE;
514 		}
515 	} else {
516 		if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) {
517 			php_error_docref(NULL, E_WARNING, "Argument #1 ($file_descriptor) must be of type int|resource, %s given",
518 				zend_zval_value_name(z_fd));
519 			RETURN_FALSE;
520 		}
521 	}
522 
523 	/* A valid file descriptor must fit in an int and be positive */
524 	if (fd < 0 || fd > INT_MAX) {
525 		RETURN_FALSE;
526 	}
527 	if (isatty(fd)) {
528 		RETURN_TRUE;
529 	} else {
530 		RETURN_FALSE;
531 	}
532 }
533 /* }}} */
534 
535 /*
536 	POSIX.1, 4.8.1 sysconf()
537 	POSIX.1, 5.7.1 pathconf(), fpathconf()
538 
539 	POSIX.1, 5.1.2 opendir(), readdir(), rewinddir(), closedir()
540 	POSIX.1, 5.2.1 chdir()
541 				already supported by PHP
542  */
543 
544 /* {{{ Get working directory pathname (POSIX.1, 5.2.2) */
PHP_FUNCTION(posix_getcwd)545 PHP_FUNCTION(posix_getcwd)
546 {
547 	char  buffer[MAXPATHLEN];
548 	char *p;
549 
550 	ZEND_PARSE_PARAMETERS_NONE();
551 
552 	p = VCWD_GETCWD(buffer, MAXPATHLEN);
553 	if (!p) {
554 		POSIX_G(last_error) = errno;
555 		RETURN_FALSE;
556 	}
557 
558 	RETURN_STRING(buffer);
559 }
560 /* }}} */
561 
562 /*
563 	POSIX.1, 5.3.x open(), creat(), umask()
564 	POSIX.1, 5.4.1 link()
565 		already supported by PHP.
566  */
567 
568 /* {{{ Make a FIFO special file (POSIX.1, 5.4.2) */
569 #ifdef HAVE_MKFIFO
PHP_FUNCTION(posix_mkfifo)570 PHP_FUNCTION(posix_mkfifo)
571 {
572 	zend_string *path;
573 	zend_long mode;
574 	int     result;
575 
576 	ZEND_PARSE_PARAMETERS_START(2, 2)
577 		Z_PARAM_PATH_STR(path)
578 		Z_PARAM_LONG(mode)
579 	ZEND_PARSE_PARAMETERS_END();
580 
581 	if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) {
582 		RETURN_FALSE;
583 	}
584 
585 	result = mkfifo(ZSTR_VAL(path), mode);
586 	if (result < 0) {
587 		POSIX_G(last_error) = errno;
588 		RETURN_FALSE;
589 	}
590 
591 	RETURN_TRUE;
592 }
593 #endif
594 /* }}} */
595 
596 /* {{{ Make a special or ordinary file (POSIX.1) */
597 #ifdef HAVE_MKNOD
PHP_FUNCTION(posix_mknod)598 PHP_FUNCTION(posix_mknod)
599 {
600 	zend_string *path;
601 	zend_long mode;
602 	zend_long major = 0, minor = 0;
603 	int result;
604 	dev_t php_dev = 0;
605 
606 	ZEND_PARSE_PARAMETERS_START(2, 4)
607 		Z_PARAM_PATH_STR(path)
608 		Z_PARAM_LONG(mode)
609 		Z_PARAM_OPTIONAL
610 		Z_PARAM_LONG(major)
611 		Z_PARAM_LONG(minor)
612 	ZEND_PARSE_PARAMETERS_END();
613 
614 	if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) {
615 		RETURN_FALSE;
616 	}
617 
618 	if ((mode & S_IFCHR) || (mode & S_IFBLK)) {
619 		if (major == 0) {
620 			zend_argument_value_error(3, "cannot be 0 for the POSIX_S_IFCHR and POSIX_S_IFBLK modes");
621 			RETURN_THROWS();
622 		} else {
623 #if defined(HAVE_MAKEDEV) || defined(makedev)
624 			php_dev = makedev(major, minor);
625 #else
626 			php_error_docref(NULL, E_WARNING, "Cannot create a block or character device, creating a normal file instead");
627 #endif
628 		}
629 	}
630 
631 	result = mknod(ZSTR_VAL(path), mode, php_dev);
632 	if (result < 0) {
633 		POSIX_G(last_error) = errno;
634 		RETURN_FALSE;
635 	}
636 
637 	RETURN_TRUE;
638 }
639 #endif
640 /* }}} */
641 
642 /* Takes a pointer to posix group and a pointer to an already initialized ZVAL
643  * array container and fills the array with the posix group member data. */
php_posix_group_to_array(struct group * g,zval * array_group)644 int php_posix_group_to_array(struct group *g, zval *array_group) /* {{{ */
645 {
646 	zval array_members;
647 	int count;
648 
649 	if (NULL == g)
650 		return 0;
651 
652 	if (array_group == NULL || Z_TYPE_P(array_group) != IS_ARRAY)
653 		return 0;
654 
655 	array_init(&array_members);
656 
657 	add_assoc_string(array_group, "name", g->gr_name);
658 	if (g->gr_passwd) {
659 		add_assoc_string(array_group, "passwd", g->gr_passwd);
660 	} else {
661 		add_assoc_null(array_group, "passwd");
662 	}
663 	for (count = 0;; count++) {
664 		/* gr_mem entries may be misaligned on macos. */
665 		char *gr_mem;
666 		memcpy(&gr_mem, &g->gr_mem[count], sizeof(char *));
667 		if (!gr_mem) {
668 			break;
669 		}
670 
671 		add_next_index_string(&array_members, gr_mem);
672 	}
673 	zend_hash_str_update(Z_ARRVAL_P(array_group), "members", sizeof("members")-1, &array_members);
674 	add_assoc_long(array_group, "gid", g->gr_gid);
675 	return 1;
676 }
677 /* }}} */
678 
679 /*
680 	POSIX.1, 5.5.1 unlink()
681 	POSIX.1, 5.5.2 rmdir()
682 	POSIX.1, 5.5.3 rename()
683 	POSIX.1, 5.6.x stat(), chmod(), utime() already supported by PHP.
684 */
685 
686 /* {{{ Determine accessibility of a file (POSIX.1 5.6.3) */
PHP_FUNCTION(posix_access)687 PHP_FUNCTION(posix_access)
688 {
689 	zend_long mode = 0;
690 	size_t filename_len, ret;
691 	char *filename, *path;
692 
693 	ZEND_PARSE_PARAMETERS_START(1, 2)
694 		Z_PARAM_PATH(filename, filename_len)
695 		Z_PARAM_OPTIONAL
696 		Z_PARAM_LONG(mode)
697 	ZEND_PARSE_PARAMETERS_END();
698 
699 	path = expand_filepath(filename, NULL);
700 	if (!path) {
701 		POSIX_G(last_error) = EIO;
702 		RETURN_FALSE;
703 	}
704 
705 	if (php_check_open_basedir_ex(path, 0)) {
706 		efree(path);
707 		POSIX_G(last_error) = EPERM;
708 		RETURN_FALSE;
709 	}
710 
711 	ret = access(path, mode);
712 	efree(path);
713 
714 	if (ret) {
715 		POSIX_G(last_error) = errno;
716 		RETURN_FALSE;
717 	}
718 
719 	RETURN_TRUE;
720 }
721 
722 #ifdef HAVE_EACCESS
PHP_FUNCTION(posix_eaccess)723 PHP_FUNCTION(posix_eaccess)
724 {
725 	zend_long mode = 0;
726 	size_t filename_len, ret;
727 	char *filename, *path;
728 
729 	ZEND_PARSE_PARAMETERS_START(1, 2)
730 		Z_PARAM_PATH(filename, filename_len)
731 		Z_PARAM_OPTIONAL
732 		Z_PARAM_LONG(mode)
733 	ZEND_PARSE_PARAMETERS_END();
734 
735 	path = expand_filepath(filename, NULL);
736 	if (!path) {
737 		zend_argument_value_error(1, "cannot be empty");
738 		RETURN_THROWS();
739 	}
740 
741 	if (php_check_open_basedir_ex(path, 0)) {
742 		efree(path);
743 		POSIX_G(last_error) = EPERM;
744 		RETURN_FALSE;
745 	}
746 
747 	ret = eaccess(path, mode);
748 	efree(path);
749 
750 	if (ret) {
751 		POSIX_G(last_error) = errno;
752 		RETURN_FALSE;
753 	}
754 
755 	RETURN_TRUE;
756 }
757 #endif
758 
759 /* }}} */
760 
761 /*
762 	POSIX.1, 6.x most I/O functions already supported by PHP.
763 	POSIX.1, 7.x tty functions, TODO
764 	POSIX.1, 8.x interactions with other C language functions
765 	POSIX.1, 9.x system database access
766 */
767 
768 /* {{{ Group database access (POSIX.1, 9.2.1) */
PHP_FUNCTION(posix_getgrnam)769 PHP_FUNCTION(posix_getgrnam)
770 {
771 	char *name;
772 	struct group *g;
773 	size_t name_len;
774 #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
775 	struct group gbuf;
776 	long buflen;
777 	char *buf;
778 #endif
779 
780 	ZEND_PARSE_PARAMETERS_START(1, 1)
781 		Z_PARAM_STRING(name, name_len)
782 	ZEND_PARSE_PARAMETERS_END();
783 
784 #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
785 	buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
786 	if (buflen < 1) {
787 		RETURN_FALSE;
788 	}
789 	buf = emalloc(buflen);
790 try_again:
791 	g = &gbuf;
792 
793 	if (getgrnam_r(name, g, buf, buflen, &g) || g == NULL) {
794 		if (errno == ERANGE) {
795 			buflen *= 2;
796 			buf = erealloc(buf, buflen);
797 			goto try_again;
798 		}
799 		POSIX_G(last_error) = errno;
800 		efree(buf);
801 		RETURN_FALSE;
802 	}
803 #else
804 	if (NULL == (g = getgrnam(name))) {
805 		POSIX_G(last_error) = errno;
806 		RETURN_FALSE;
807 	}
808 #endif
809 	array_init(return_value);
810 
811 	if (!php_posix_group_to_array(g, return_value)) {
812 		zend_array_destroy(Z_ARR_P(return_value));
813 		php_error_docref(NULL, E_WARNING, "Unable to convert posix group to array");
814 		RETVAL_FALSE;
815 	}
816 #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
817 	efree(buf);
818 #endif
819 }
820 /* }}} */
821 
822 /* {{{ Group database access (POSIX.1, 9.2.1) */
PHP_FUNCTION(posix_getgrgid)823 PHP_FUNCTION(posix_getgrgid)
824 {
825 	zend_long gid;
826 #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
827 	int ret;
828 	struct group _g;
829 	struct group *retgrptr = NULL;
830 	long grbuflen;
831 	char *grbuf;
832 #endif
833 	struct group *g;
834 
835 	ZEND_PARSE_PARAMETERS_START(1, 1)
836 		Z_PARAM_LONG(gid)
837 	ZEND_PARSE_PARAMETERS_END();
838 
839 #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
840 
841 	grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
842 	if (grbuflen < 1) {
843 		RETURN_FALSE;
844 	}
845 
846 	grbuf = emalloc(grbuflen);
847 
848 try_again:
849 	ret = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr);
850 	if (ret || retgrptr == NULL) {
851 		if (errno == ERANGE) {
852 			grbuflen *= 2;
853 			grbuf = erealloc(grbuf, grbuflen);
854 			goto try_again;
855 		}
856 		POSIX_G(last_error) = ret;
857 		efree(grbuf);
858 		RETURN_FALSE;
859 	}
860 	g = &_g;
861 #else
862 	if (NULL == (g = getgrgid(gid))) {
863 		POSIX_G(last_error) = errno;
864 		RETURN_FALSE;
865 	}
866 #endif
867 	array_init(return_value);
868 
869 	if (!php_posix_group_to_array(g, return_value)) {
870 		zend_array_destroy(Z_ARR_P(return_value));
871 		php_error_docref(NULL, E_WARNING, "Unable to convert posix group struct to array");
872 		RETVAL_FALSE;
873 	}
874 #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
875 	efree(grbuf);
876 #endif
877 }
878 /* }}} */
879 
php_posix_passwd_to_array(struct passwd * pw,zval * return_value)880 int php_posix_passwd_to_array(struct passwd *pw, zval *return_value) /* {{{ */
881 {
882 	if (NULL == pw)
883 		return 0;
884 	if (NULL == return_value || Z_TYPE_P(return_value) != IS_ARRAY)
885 		return 0;
886 
887 	add_assoc_string(return_value, "name",      pw->pw_name);
888 	add_assoc_string(return_value, "passwd",    pw->pw_passwd);
889 	add_assoc_long  (return_value, "uid",       pw->pw_uid);
890 	add_assoc_long  (return_value, "gid",		pw->pw_gid);
891 	add_assoc_string(return_value, "gecos",     pw->pw_gecos);
892 	add_assoc_string(return_value, "dir",       pw->pw_dir);
893 	add_assoc_string(return_value, "shell",     pw->pw_shell);
894 	return 1;
895 }
896 /* }}} */
897 
898 /* {{{ User database access (POSIX.1, 9.2.2) */
PHP_FUNCTION(posix_getpwnam)899 PHP_FUNCTION(posix_getpwnam)
900 {
901 	struct passwd *pw;
902 	char *name;
903 	size_t name_len;
904 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
905 	struct passwd pwbuf;
906 	long buflen;
907 	char *buf;
908 #endif
909 
910 	ZEND_PARSE_PARAMETERS_START(1, 1)
911 		Z_PARAM_STRING(name, name_len)
912 	ZEND_PARSE_PARAMETERS_END();
913 
914 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
915 	buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
916 	if (buflen < 1) {
917 		RETURN_FALSE;
918 	}
919 	buf = emalloc(buflen);
920 	pw = &pwbuf;
921 
922 try_again:
923 	if (getpwnam_r(name, pw, buf, buflen, &pw) || pw == NULL) {
924 		if (errno == ERANGE) {
925 			buflen *= 2;
926 			buf = erealloc(buf, buflen);
927 			goto try_again;
928 		}
929 		efree(buf);
930 		POSIX_G(last_error) = errno;
931 		RETURN_FALSE;
932 	}
933 #else
934 	if (NULL == (pw = getpwnam(name))) {
935 		POSIX_G(last_error) = errno;
936 		RETURN_FALSE;
937 	}
938 #endif
939 	array_init(return_value);
940 
941 	if (!php_posix_passwd_to_array(pw, return_value)) {
942 		zend_array_destroy(Z_ARR_P(return_value));
943 		php_error_docref(NULL, E_WARNING, "Unable to convert posix passwd struct to array");
944 		RETVAL_FALSE;
945 	}
946 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
947 	efree(buf);
948 #endif
949 }
950 /* }}} */
951 
952 /* {{{ User database access (POSIX.1, 9.2.2) */
PHP_FUNCTION(posix_getpwuid)953 PHP_FUNCTION(posix_getpwuid)
954 {
955 	zend_long uid;
956 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
957 	struct passwd _pw;
958 	struct passwd *retpwptr = NULL;
959 	long pwbuflen;
960 	char *pwbuf;
961 	int ret;
962 #endif
963 	struct passwd *pw;
964 
965 	ZEND_PARSE_PARAMETERS_START(1, 1)
966 		Z_PARAM_LONG(uid)
967 	ZEND_PARSE_PARAMETERS_END();
968 
969 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
970 	pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
971 	if (pwbuflen < 1) {
972 		RETURN_FALSE;
973 	}
974 	pwbuf = emalloc(pwbuflen);
975 
976 try_again:
977 	ret = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr);
978 	if (ret || retpwptr == NULL) {
979 		if (errno == ERANGE) {
980 			pwbuflen *= 2;
981 			pwbuf = erealloc(pwbuf, pwbuflen);
982 			goto try_again;
983 		}
984 		POSIX_G(last_error) = ret;
985 		efree(pwbuf);
986 		RETURN_FALSE;
987 	}
988 	pw = &_pw;
989 #else
990 	if (NULL == (pw = getpwuid(uid))) {
991 		POSIX_G(last_error) = errno;
992 		RETURN_FALSE;
993 	}
994 #endif
995 	array_init(return_value);
996 
997 	if (!php_posix_passwd_to_array(pw, return_value)) {
998 		zend_array_destroy(Z_ARR_P(return_value));
999 		php_error_docref(NULL, E_WARNING, "Unable to convert posix passwd struct to array");
1000 		RETVAL_FALSE;
1001 	}
1002 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
1003 	efree(pwbuf);
1004 #endif
1005 }
1006 /* }}} */
1007 
1008 
1009 #ifdef HAVE_GETRLIMIT
1010 
1011 #define UNLIMITED_STRING "unlimited"
1012 
1013 /* {{{ posix_addlimit */
posix_addlimit(int limit,const char * name,zval * return_value)1014 static int posix_addlimit(int limit, const char *name, zval *return_value) {
1015 	int result;
1016 	struct rlimit rl;
1017 	char hard[80];
1018 	char soft[80];
1019 
1020 	snprintf(hard, 80, "hard %s", name);
1021 	snprintf(soft, 80, "soft %s", name);
1022 
1023 	result = getrlimit(limit, &rl);
1024 	if (result < 0) {
1025 		POSIX_G(last_error) = errno;
1026 		return FAILURE;
1027 	}
1028 
1029 	if (rl.rlim_cur == RLIM_INFINITY) {
1030 		add_assoc_stringl(return_value, soft, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1);
1031 	} else {
1032 		add_assoc_long(return_value, soft, rl.rlim_cur);
1033 	}
1034 
1035 	if (rl.rlim_max == RLIM_INFINITY) {
1036 		add_assoc_stringl(return_value, hard, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1);
1037 	} else {
1038 		add_assoc_long(return_value, hard, rl.rlim_max);
1039 	}
1040 
1041 	return SUCCESS;
1042 }
1043 /* }}} */
1044 
1045 /* {{{ limits[] */
1046 static const struct limitlist {
1047 	int limit;
1048 	const char *name;
1049 } limits[] = {
1050 #ifdef RLIMIT_CORE
1051 	{ RLIMIT_CORE,	"core" },
1052 #endif
1053 
1054 #ifdef RLIMIT_DATA
1055 	{ RLIMIT_DATA,	"data" },
1056 #endif
1057 
1058 #ifdef RLIMIT_STACK
1059 	{ RLIMIT_STACK,	"stack" },
1060 #endif
1061 
1062 #ifdef RLIMIT_VMEM
1063 	{ RLIMIT_VMEM, "virtualmem" },
1064 #endif
1065 
1066 #ifdef RLIMIT_AS
1067 	{ RLIMIT_AS, "totalmem" },
1068 #endif
1069 
1070 #ifdef RLIMIT_RSS
1071 	{ RLIMIT_RSS, "rss" },
1072 #endif
1073 
1074 #ifdef RLIMIT_NPROC
1075 	{ RLIMIT_NPROC, "maxproc" },
1076 #endif
1077 
1078 #ifdef RLIMIT_MEMLOCK
1079 	{ RLIMIT_MEMLOCK, "memlock" },
1080 #endif
1081 
1082 #ifdef RLIMIT_CPU
1083 	{ RLIMIT_CPU,	"cpu" },
1084 #endif
1085 
1086 #ifdef RLIMIT_FSIZE
1087 	{ RLIMIT_FSIZE, "filesize" },
1088 #endif
1089 
1090 #ifdef RLIMIT_NOFILE
1091 	{ RLIMIT_NOFILE, "openfiles" },
1092 #endif
1093 
1094 #ifdef RLIMIT_OFILE
1095 	{ RLIMIT_OFILE, "openfiles" },
1096 #endif
1097 
1098 #ifdef RLIMIT_KQUEUES
1099 	{ RLIMIT_KQUEUES, "kqueues" },
1100 #endif
1101 
1102 #ifdef RLIMIT_NPTS
1103 	{ RLIMIT_NPTS, "npts" },
1104 #endif
1105 
1106 	{ 0, NULL }
1107 };
1108 /* }}} */
1109 
1110 
1111 /* {{{ Get system resource consumption limits (This is not a POSIX function, but a BSDism and a SVR4ism. We compile conditionally) */
PHP_FUNCTION(posix_getrlimit)1112 PHP_FUNCTION(posix_getrlimit)
1113 {
1114 	const struct limitlist *l = NULL;
1115 	zend_long res;
1116 	bool res_is_null = true;
1117 
1118 	ZEND_PARSE_PARAMETERS_START(0, 1)
1119 		Z_PARAM_OPTIONAL
1120 		Z_PARAM_LONG_OR_NULL(res, res_is_null)
1121 	ZEND_PARSE_PARAMETERS_END();
1122 
1123 	if (res_is_null) {
1124 		array_init(return_value);
1125 
1126 		for (l=limits; l->name; l++) {
1127 			if (posix_addlimit(l->limit, l->name, return_value) == FAILURE) {
1128 				zend_array_destroy(Z_ARR_P(return_value));
1129 				RETURN_FALSE;
1130 			}
1131 		}
1132 	} else {
1133 		struct rlimit rl;
1134 		int result = getrlimit(res, &rl);
1135 		if (result < 0) {
1136 			POSIX_G(last_error) = errno;
1137 			RETURN_FALSE;
1138 		}
1139 
1140 		array_init(return_value);
1141 		if (rl.rlim_cur == RLIM_INFINITY) {
1142 			add_next_index_stringl(return_value, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1);
1143 		} else {
1144 			add_next_index_long(return_value, rl.rlim_cur);
1145 		}
1146 
1147 		if (rl.rlim_max == RLIM_INFINITY) {
1148 			add_next_index_stringl(return_value, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1);
1149 		} else {
1150 			add_next_index_long(return_value, rl.rlim_max);
1151 		}
1152 	}
1153 }
1154 /* }}} */
1155 
1156 #endif /* HAVE_GETRLIMIT */
1157 
1158 #ifdef HAVE_SETRLIMIT
1159 /* {{{ Set system resource consumption limits (POSIX.1-2001) */
PHP_FUNCTION(posix_setrlimit)1160 PHP_FUNCTION(posix_setrlimit)
1161 {
1162 	struct rlimit rl;
1163 	zend_long res, cur, max;
1164 
1165 	ZEND_PARSE_PARAMETERS_START(3, 3)
1166 		Z_PARAM_LONG(res)
1167 		Z_PARAM_LONG(cur)
1168 		Z_PARAM_LONG(max)
1169 	ZEND_PARSE_PARAMETERS_END();
1170 
1171 	rl.rlim_cur = cur;
1172 	rl.rlim_max = max;
1173 
1174 	if (setrlimit(res, &rl) == -1) {
1175 		POSIX_G(last_error) = errno;
1176 		RETURN_FALSE;
1177 	}
1178 
1179 	RETURN_TRUE;
1180 }
1181 /* }}} */
1182 
1183 #endif /* HAVE_SETRLIMIT */
1184 
1185 
1186 /* {{{ Retrieve the error number set by the last posix function which failed. */
PHP_FUNCTION(posix_get_last_error)1187 PHP_FUNCTION(posix_get_last_error)
1188 {
1189 	ZEND_PARSE_PARAMETERS_NONE();
1190 
1191 	RETURN_LONG(POSIX_G(last_error));
1192 }
1193 /* }}} */
1194 
1195 /* {{{ Retrieve the system error message associated with the given errno. */
PHP_FUNCTION(posix_strerror)1196 PHP_FUNCTION(posix_strerror)
1197 {
1198 	zend_long error;
1199 
1200 	ZEND_PARSE_PARAMETERS_START(1, 1)
1201 		Z_PARAM_LONG(error)
1202 	ZEND_PARSE_PARAMETERS_END();
1203 
1204 	RETURN_STRING(strerror(error));
1205 }
1206 /* }}} */
1207 
1208 #endif
1209 
1210 #ifdef HAVE_INITGROUPS
1211 /* {{{ Calculate the group access list for the user specified in name. */
PHP_FUNCTION(posix_initgroups)1212 PHP_FUNCTION(posix_initgroups)
1213 {
1214 	zend_long basegid;
1215 	char *name;
1216 	size_t name_len;
1217 
1218 	ZEND_PARSE_PARAMETERS_START(2, 2)
1219 		Z_PARAM_STRING(name, name_len)
1220 		Z_PARAM_LONG(basegid)
1221 	ZEND_PARSE_PARAMETERS_END();
1222 
1223 	if (name_len == 0) {
1224 		RETURN_FALSE;
1225 	}
1226 
1227 	RETURN_BOOL(!initgroups((const char *)name, basegid));
1228 }
1229 /* }}} */
1230 #endif
1231 
PHP_FUNCTION(posix_sysconf)1232 PHP_FUNCTION(posix_sysconf)
1233 {
1234 	zend_long conf_id;
1235 
1236 	ZEND_PARSE_PARAMETERS_START(1, 1)
1237 		Z_PARAM_LONG(conf_id)
1238 	ZEND_PARSE_PARAMETERS_END();
1239 
1240 	RETURN_LONG(sysconf(conf_id));
1241 }
1242 
1243 #ifdef HAVE_PATHCONF
PHP_FUNCTION(posix_pathconf)1244 PHP_FUNCTION(posix_pathconf)
1245 {
1246 	zend_long name, ret;
1247 	char *path;
1248 	size_t path_len;
1249 
1250 	ZEND_PARSE_PARAMETERS_START(2, 2)
1251 		Z_PARAM_PATH(path, path_len)
1252 		Z_PARAM_LONG(name);
1253 	ZEND_PARSE_PARAMETERS_END();
1254 
1255 	if (path_len == 0) {
1256 		zend_argument_value_error(1, "cannot be empty");
1257 		RETURN_THROWS();
1258 	} else if (php_check_open_basedir(path)) {
1259 		php_error_docref(NULL, E_WARNING, "Invalid path supplied: %s", path);
1260 		RETURN_FALSE;
1261 	}
1262 
1263 	ret = pathconf(path, name);
1264 
1265 	if (ret < 0 && errno != 0) {
1266 		POSIX_G(last_error) = errno;
1267 		RETURN_FALSE;
1268 	}
1269 
1270 	RETURN_LONG(ret);
1271 }
1272 #endif
1273 
1274 #ifdef HAVE_FPATHCONF
PHP_FUNCTION(posix_fpathconf)1275 PHP_FUNCTION(posix_fpathconf)
1276 {
1277 	zend_long name, ret, fd = 0;
1278 	zval *z_fd;
1279 
1280 	ZEND_PARSE_PARAMETERS_START(2, 2)
1281 		Z_PARAM_ZVAL(z_fd)
1282 		Z_PARAM_LONG(name);
1283 	ZEND_PARSE_PARAMETERS_END();
1284 
1285 	if (Z_TYPE_P(z_fd) == IS_RESOURCE) {
1286 		if (!php_posix_stream_get_fd(z_fd, &fd)) {
1287 			RETURN_FALSE;
1288 		}
1289 	} else {
1290 		if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) {
1291 			zend_argument_type_error(1, "must be of type int|resource, %s given",
1292 				zend_zval_value_name(z_fd));
1293 			RETURN_THROWS();
1294 		}
1295 	}
1296 
1297 	ret = fpathconf(fd, name);
1298 
1299 	if (ret < 0 && errno != 0) {
1300 		POSIX_G(last_error) = errno;
1301 		RETURN_FALSE;
1302 	}
1303 
1304 	RETURN_LONG(ret);
1305 }
1306 #endif
1307