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