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