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(DARWIN) && defined(HAVE_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,int * fd)420 static int php_posix_stream_get_fd(zval *zfp, int *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 if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT) == SUCCESS) {
430 php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT, (void*)fd, 0);
431 } else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS) {
432 php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)fd, 0);
433 } else {
434 php_error_docref(NULL, E_WARNING, "Could not use stream of type '%s'",
435 stream->ops->label);
436 return 0;
437 }
438 return 1;
439 }
440 /* }}} */
441
442 /* {{{ Determine terminal device name (POSIX.1, 4.7.2) */
PHP_FUNCTION(posix_ttyname)443 PHP_FUNCTION(posix_ttyname)
444 {
445 zval *z_fd;
446 char *p;
447 int fd;
448 #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
449 zend_long buflen;
450 int err;
451 #endif
452
453 ZEND_PARSE_PARAMETERS_START(1, 1)
454 Z_PARAM_ZVAL(z_fd)
455 ZEND_PARSE_PARAMETERS_END();
456
457 switch (Z_TYPE_P(z_fd)) {
458 case IS_RESOURCE:
459 if (!php_posix_stream_get_fd(z_fd, &fd)) {
460 RETURN_FALSE;
461 }
462 break;
463 default:
464 fd = zval_get_long(z_fd);
465 }
466 #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
467 buflen = sysconf(_SC_TTY_NAME_MAX);
468 if (buflen < 1) {
469 buflen = 32;
470 }
471 #if ZEND_DEBUG
472 /* Test retry logic */
473 buflen = 1;
474 #endif
475 p = emalloc(buflen);
476
477 try_again:
478 err = ttyname_r(fd, p, buflen);
479 if (err) {
480 if (err == ERANGE) {
481 buflen *= 2;
482 p = erealloc(p, buflen);
483 goto try_again;
484 }
485 POSIX_G(last_error) = err;
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 int fd;
506
507 ZEND_PARSE_PARAMETERS_START(1, 1)
508 Z_PARAM_ZVAL(z_fd)
509 ZEND_PARSE_PARAMETERS_END();
510
511 switch (Z_TYPE_P(z_fd)) {
512 case IS_RESOURCE:
513 if (!php_posix_stream_get_fd(z_fd, &fd)) {
514 RETURN_FALSE;
515 }
516 break;
517 default:
518 fd = zval_get_long(z_fd);
519 }
520
521 if (isatty(fd)) {
522 RETURN_TRUE;
523 } else {
524 RETURN_FALSE;
525 }
526 }
527 /* }}} */
528
529 /*
530 POSIX.1, 4.8.1 sysconf() - TODO
531 POSIX.1, 5.7.1 pathconf(), fpathconf() - TODO
532
533 POSIX.1, 5.1.2 opendir(), readdir(), rewinddir(), closedir()
534 POSIX.1, 5.2.1 chdir()
535 already supported by PHP
536 */
537
538 /* {{{ Get working directory pathname (POSIX.1, 5.2.2) */
PHP_FUNCTION(posix_getcwd)539 PHP_FUNCTION(posix_getcwd)
540 {
541 char buffer[MAXPATHLEN];
542 char *p;
543
544 ZEND_PARSE_PARAMETERS_NONE();
545
546 p = VCWD_GETCWD(buffer, MAXPATHLEN);
547 if (!p) {
548 POSIX_G(last_error) = errno;
549 RETURN_FALSE;
550 }
551
552 RETURN_STRING(buffer);
553 }
554 /* }}} */
555
556 /*
557 POSIX.1, 5.3.x open(), creat(), umask()
558 POSIX.1, 5.4.1 link()
559 already supported by PHP.
560 */
561
562 /* {{{ Make a FIFO special file (POSIX.1, 5.4.2) */
563 #ifdef HAVE_MKFIFO
PHP_FUNCTION(posix_mkfifo)564 PHP_FUNCTION(posix_mkfifo)
565 {
566 zend_string *path;
567 zend_long mode;
568 int result;
569
570 ZEND_PARSE_PARAMETERS_START(2, 2)
571 Z_PARAM_PATH_STR(path)
572 Z_PARAM_LONG(mode)
573 ZEND_PARSE_PARAMETERS_END();
574
575 if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) {
576 RETURN_FALSE;
577 }
578
579 result = mkfifo(ZSTR_VAL(path), mode);
580 if (result < 0) {
581 POSIX_G(last_error) = errno;
582 RETURN_FALSE;
583 }
584
585 RETURN_TRUE;
586 }
587 #endif
588 /* }}} */
589
590 /* {{{ Make a special or ordinary file (POSIX.1) */
591 #ifdef HAVE_MKNOD
PHP_FUNCTION(posix_mknod)592 PHP_FUNCTION(posix_mknod)
593 {
594 zend_string *path;
595 zend_long mode;
596 zend_long major = 0, minor = 0;
597 int result;
598 dev_t php_dev = 0;
599
600 ZEND_PARSE_PARAMETERS_START(2, 4)
601 Z_PARAM_PATH_STR(path)
602 Z_PARAM_LONG(mode)
603 Z_PARAM_OPTIONAL
604 Z_PARAM_LONG(major)
605 Z_PARAM_LONG(minor)
606 ZEND_PARSE_PARAMETERS_END();
607
608 if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) {
609 RETURN_FALSE;
610 }
611
612 if ((mode & S_IFCHR) || (mode & S_IFBLK)) {
613 if (major == 0) {
614 zend_argument_value_error(3, "cannot be 0 for the POSIX_S_IFCHR and POSIX_S_IFBLK modes");
615 RETURN_THROWS();
616 } else {
617 #if defined(HAVE_MAKEDEV) || defined(makedev)
618 php_dev = makedev(major, minor);
619 #else
620 php_error_docref(NULL, E_WARNING, "Cannot create a block or character device, creating a normal file instead");
621 #endif
622 }
623 }
624
625 result = mknod(ZSTR_VAL(path), mode, php_dev);
626 if (result < 0) {
627 POSIX_G(last_error) = errno;
628 RETURN_FALSE;
629 }
630
631 RETURN_TRUE;
632 }
633 #endif
634 /* }}} */
635
636 /* Takes a pointer to posix group and a pointer to an already initialized ZVAL
637 * array container and fills the array with the posix group member data. */
php_posix_group_to_array(struct group * g,zval * array_group)638 int php_posix_group_to_array(struct group *g, zval *array_group) /* {{{ */
639 {
640 zval array_members;
641 int count;
642
643 if (NULL == g)
644 return 0;
645
646 if (array_group == NULL || Z_TYPE_P(array_group) != IS_ARRAY)
647 return 0;
648
649 array_init(&array_members);
650
651 add_assoc_string(array_group, "name", g->gr_name);
652 if (g->gr_passwd) {
653 add_assoc_string(array_group, "passwd", g->gr_passwd);
654 } else {
655 add_assoc_null(array_group, "passwd");
656 }
657 for (count = 0;; count++) {
658 /* gr_mem entries may be misaligned on macos. */
659 char *gr_mem;
660 memcpy(&gr_mem, &g->gr_mem[count], sizeof(char *));
661 if (!gr_mem) {
662 break;
663 }
664
665 add_next_index_string(&array_members, gr_mem);
666 }
667 zend_hash_str_update(Z_ARRVAL_P(array_group), "members", sizeof("members")-1, &array_members);
668 add_assoc_long(array_group, "gid", g->gr_gid);
669 return 1;
670 }
671 /* }}} */
672
673 /*
674 POSIX.1, 5.5.1 unlink()
675 POSIX.1, 5.5.2 rmdir()
676 POSIX.1, 5.5.3 rename()
677 POSIX.1, 5.6.x stat(), chmod(), utime() already supported by PHP.
678 */
679
680 /* {{{ Determine accessibility of a file (POSIX.1 5.6.3) */
PHP_FUNCTION(posix_access)681 PHP_FUNCTION(posix_access)
682 {
683 zend_long mode = 0;
684 size_t filename_len, ret;
685 char *filename, *path;
686
687 ZEND_PARSE_PARAMETERS_START(1, 2)
688 Z_PARAM_PATH(filename, filename_len)
689 Z_PARAM_OPTIONAL
690 Z_PARAM_LONG(mode)
691 ZEND_PARSE_PARAMETERS_END();
692
693 path = expand_filepath(filename, NULL);
694 if (!path) {
695 POSIX_G(last_error) = EIO;
696 RETURN_FALSE;
697 }
698
699 if (php_check_open_basedir_ex(path, 0)) {
700 efree(path);
701 POSIX_G(last_error) = EPERM;
702 RETURN_FALSE;
703 }
704
705 ret = access(path, mode);
706 efree(path);
707
708 if (ret) {
709 POSIX_G(last_error) = errno;
710 RETURN_FALSE;
711 }
712
713 RETURN_TRUE;
714 }
715 /* }}} */
716
717 /*
718 POSIX.1, 6.x most I/O functions already supported by PHP.
719 POSIX.1, 7.x tty functions, TODO
720 POSIX.1, 8.x interactions with other C language functions
721 POSIX.1, 9.x system database access
722 */
723
724 /* {{{ Group database access (POSIX.1, 9.2.1) */
PHP_FUNCTION(posix_getgrnam)725 PHP_FUNCTION(posix_getgrnam)
726 {
727 char *name;
728 struct group *g;
729 size_t name_len;
730 #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
731 struct group gbuf;
732 long buflen;
733 char *buf;
734 int err;
735 #endif
736
737 ZEND_PARSE_PARAMETERS_START(1, 1)
738 Z_PARAM_STRING(name, name_len)
739 ZEND_PARSE_PARAMETERS_END();
740
741 #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
742 buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
743 if (buflen < 1) {
744 buflen = 1024;
745 }
746 #if ZEND_DEBUG
747 /* Test retry logic */
748 buflen = 1;
749 #endif
750 buf = emalloc(buflen);
751 try_again:
752 g = &gbuf;
753
754 err = getgrnam_r(name, g, buf, buflen, &g);
755 if (err || g == NULL) {
756 if (err == ERANGE) {
757 buflen *= 2;
758 buf = erealloc(buf, buflen);
759 goto try_again;
760 }
761 POSIX_G(last_error) = err;
762 efree(buf);
763 RETURN_FALSE;
764 }
765 #else
766 if (NULL == (g = getgrnam(name))) {
767 POSIX_G(last_error) = errno;
768 RETURN_FALSE;
769 }
770 #endif
771 array_init(return_value);
772
773 if (!php_posix_group_to_array(g, return_value)) {
774 zend_array_destroy(Z_ARR_P(return_value));
775 php_error_docref(NULL, E_WARNING, "Unable to convert posix group to array");
776 RETVAL_FALSE;
777 }
778 #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
779 efree(buf);
780 #endif
781 }
782 /* }}} */
783
784 /* {{{ Group database access (POSIX.1, 9.2.1) */
PHP_FUNCTION(posix_getgrgid)785 PHP_FUNCTION(posix_getgrgid)
786 {
787 zend_long gid;
788 #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
789 int err;
790 struct group _g;
791 struct group *retgrptr = NULL;
792 long grbuflen;
793 char *grbuf;
794 #endif
795 struct group *g;
796
797 ZEND_PARSE_PARAMETERS_START(1, 1)
798 Z_PARAM_LONG(gid)
799 ZEND_PARSE_PARAMETERS_END();
800
801 #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
802
803 grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
804 if (grbuflen < 1) {
805 grbuflen = 1024;
806 }
807 #if ZEND_DEBUG
808 /* Test retry logic */
809 grbuflen = 1;
810 #endif
811
812 grbuf = emalloc(grbuflen);
813
814 try_again:
815 err = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr);
816 if (err || retgrptr == NULL) {
817 if (err == ERANGE) {
818 grbuflen *= 2;
819 grbuf = erealloc(grbuf, grbuflen);
820 goto try_again;
821 }
822 POSIX_G(last_error) = err;
823 efree(grbuf);
824 RETURN_FALSE;
825 }
826 g = &_g;
827 #else
828 if (NULL == (g = getgrgid(gid))) {
829 POSIX_G(last_error) = errno;
830 RETURN_FALSE;
831 }
832 #endif
833 array_init(return_value);
834
835 if (!php_posix_group_to_array(g, return_value)) {
836 zend_array_destroy(Z_ARR_P(return_value));
837 php_error_docref(NULL, E_WARNING, "Unable to convert posix group struct to array");
838 RETVAL_FALSE;
839 }
840 #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
841 efree(grbuf);
842 #endif
843 }
844 /* }}} */
845
php_posix_passwd_to_array(struct passwd * pw,zval * return_value)846 int php_posix_passwd_to_array(struct passwd *pw, zval *return_value) /* {{{ */
847 {
848 if (NULL == pw)
849 return 0;
850 if (NULL == return_value || Z_TYPE_P(return_value) != IS_ARRAY)
851 return 0;
852
853 add_assoc_string(return_value, "name", pw->pw_name);
854 add_assoc_string(return_value, "passwd", pw->pw_passwd);
855 add_assoc_long (return_value, "uid", pw->pw_uid);
856 add_assoc_long (return_value, "gid", pw->pw_gid);
857 add_assoc_string(return_value, "gecos", pw->pw_gecos);
858 add_assoc_string(return_value, "dir", pw->pw_dir);
859 add_assoc_string(return_value, "shell", pw->pw_shell);
860 return 1;
861 }
862 /* }}} */
863
864 /* {{{ User database access (POSIX.1, 9.2.2) */
PHP_FUNCTION(posix_getpwnam)865 PHP_FUNCTION(posix_getpwnam)
866 {
867 struct passwd *pw;
868 char *name;
869 size_t name_len;
870 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
871 struct passwd pwbuf;
872 long buflen;
873 char *buf;
874 int err;
875 #endif
876
877 ZEND_PARSE_PARAMETERS_START(1, 1)
878 Z_PARAM_STRING(name, name_len)
879 ZEND_PARSE_PARAMETERS_END();
880
881 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
882 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
883 if (buflen < 1) {
884 buflen = 1024;
885 }
886 #if ZEND_DEBUG
887 /* Test retry logic */
888 buflen = 1;
889 #endif
890 buf = emalloc(buflen);
891
892 try_again:
893 pw = &pwbuf;
894 err = getpwnam_r(name, pw, buf, buflen, &pw);
895 if (err || pw == NULL) {
896 if (err == ERANGE) {
897 buflen *= 2;
898 buf = erealloc(buf, buflen);
899 goto try_again;
900 }
901 efree(buf);
902 POSIX_G(last_error) = err;
903 RETURN_FALSE;
904 }
905 #else
906 if (NULL == (pw = getpwnam(name))) {
907 POSIX_G(last_error) = errno;
908 RETURN_FALSE;
909 }
910 #endif
911 array_init(return_value);
912
913 if (!php_posix_passwd_to_array(pw, return_value)) {
914 zend_array_destroy(Z_ARR_P(return_value));
915 php_error_docref(NULL, E_WARNING, "Unable to convert posix passwd struct to array");
916 RETVAL_FALSE;
917 }
918 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
919 efree(buf);
920 #endif
921 }
922 /* }}} */
923
924 /* {{{ User database access (POSIX.1, 9.2.2) */
PHP_FUNCTION(posix_getpwuid)925 PHP_FUNCTION(posix_getpwuid)
926 {
927 zend_long uid;
928 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
929 struct passwd _pw;
930 struct passwd *retpwptr = NULL;
931 long pwbuflen;
932 char *pwbuf;
933 int err;
934 #endif
935 struct passwd *pw;
936
937 ZEND_PARSE_PARAMETERS_START(1, 1)
938 Z_PARAM_LONG(uid)
939 ZEND_PARSE_PARAMETERS_END();
940
941 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
942 pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
943 if (pwbuflen < 1) {
944 pwbuflen = 1024;
945 }
946 #if ZEND_DEBUG
947 /* Test retry logic */
948 pwbuflen = 1;
949 #endif
950 pwbuf = emalloc(pwbuflen);
951
952 try_again:
953 err = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr);
954 if (err || retpwptr == NULL) {
955 if (err == ERANGE) {
956 pwbuflen *= 2;
957 pwbuf = erealloc(pwbuf, pwbuflen);
958 goto try_again;
959 }
960 POSIX_G(last_error) = err;
961 efree(pwbuf);
962 RETURN_FALSE;
963 }
964 pw = &_pw;
965 #else
966 if (NULL == (pw = getpwuid(uid))) {
967 POSIX_G(last_error) = errno;
968 RETURN_FALSE;
969 }
970 #endif
971 array_init(return_value);
972
973 if (!php_posix_passwd_to_array(pw, return_value)) {
974 zend_array_destroy(Z_ARR_P(return_value));
975 php_error_docref(NULL, E_WARNING, "Unable to convert posix passwd struct to array");
976 RETVAL_FALSE;
977 }
978 #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
979 efree(pwbuf);
980 #endif
981 }
982 /* }}} */
983
984
985 #ifdef HAVE_GETRLIMIT
986
987 #define UNLIMITED_STRING "unlimited"
988
989 /* {{{ posix_addlimit */
posix_addlimit(int limit,const char * name,zval * return_value)990 static int posix_addlimit(int limit, const char *name, zval *return_value) {
991 int result;
992 struct rlimit rl;
993 char hard[80];
994 char soft[80];
995
996 snprintf(hard, 80, "hard %s", name);
997 snprintf(soft, 80, "soft %s", name);
998
999 result = getrlimit(limit, &rl);
1000 if (result < 0) {
1001 POSIX_G(last_error) = errno;
1002 return FAILURE;
1003 }
1004
1005 if (rl.rlim_cur == RLIM_INFINITY) {
1006 add_assoc_stringl(return_value, soft, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1);
1007 } else {
1008 add_assoc_long(return_value, soft, rl.rlim_cur);
1009 }
1010
1011 if (rl.rlim_max == RLIM_INFINITY) {
1012 add_assoc_stringl(return_value, hard, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1);
1013 } else {
1014 add_assoc_long(return_value, hard, rl.rlim_max);
1015 }
1016
1017 return SUCCESS;
1018 }
1019 /* }}} */
1020
1021 /* {{{ limits[] */
1022 static const struct limitlist {
1023 int limit;
1024 const char *name;
1025 } limits[] = {
1026 #ifdef RLIMIT_CORE
1027 { RLIMIT_CORE, "core" },
1028 #endif
1029
1030 #ifdef RLIMIT_DATA
1031 { RLIMIT_DATA, "data" },
1032 #endif
1033
1034 #ifdef RLIMIT_STACK
1035 { RLIMIT_STACK, "stack" },
1036 #endif
1037
1038 #ifdef RLIMIT_VMEM
1039 { RLIMIT_VMEM, "virtualmem" },
1040 #endif
1041
1042 #ifdef RLIMIT_AS
1043 { RLIMIT_AS, "totalmem" },
1044 #endif
1045
1046 #ifdef RLIMIT_RSS
1047 { RLIMIT_RSS, "rss" },
1048 #endif
1049
1050 #ifdef RLIMIT_NPROC
1051 { RLIMIT_NPROC, "maxproc" },
1052 #endif
1053
1054 #ifdef RLIMIT_MEMLOCK
1055 { RLIMIT_MEMLOCK, "memlock" },
1056 #endif
1057
1058 #ifdef RLIMIT_CPU
1059 { RLIMIT_CPU, "cpu" },
1060 #endif
1061
1062 #ifdef RLIMIT_FSIZE
1063 { RLIMIT_FSIZE, "filesize" },
1064 #endif
1065
1066 #ifdef RLIMIT_NOFILE
1067 { RLIMIT_NOFILE, "openfiles" },
1068 #endif
1069
1070 #ifdef RLIMIT_OFILE
1071 { RLIMIT_OFILE, "openfiles" },
1072 #endif
1073
1074 #ifdef RLIMIT_KQUEUES
1075 { RLIMIT_KQUEUES, "kqueues" },
1076 #endif
1077
1078 #ifdef RLIMIT_NPTS
1079 { RLIMIT_NPTS, "npts" },
1080 #endif
1081
1082 { 0, NULL }
1083 };
1084 /* }}} */
1085
1086
1087 /* {{{ Get system resource consumption limits (This is not a POSIX function, but a BSDism and a SVR4ism. We compile conditionally) */
PHP_FUNCTION(posix_getrlimit)1088 PHP_FUNCTION(posix_getrlimit)
1089 {
1090 const struct limitlist *l = NULL;
1091
1092 ZEND_PARSE_PARAMETERS_NONE();
1093
1094 array_init(return_value);
1095
1096 for (l=limits; l->name; l++) {
1097 if (posix_addlimit(l->limit, l->name, return_value) == FAILURE) {
1098 zend_array_destroy(Z_ARR_P(return_value));
1099 RETURN_FALSE;
1100 }
1101 }
1102 }
1103 /* }}} */
1104
1105 #endif /* HAVE_GETRLIMIT */
1106
1107 #ifdef HAVE_SETRLIMIT
1108 /* {{{ Set system resource consumption limits (POSIX.1-2001) */
PHP_FUNCTION(posix_setrlimit)1109 PHP_FUNCTION(posix_setrlimit)
1110 {
1111 struct rlimit rl;
1112 zend_long res, cur, max;
1113
1114 ZEND_PARSE_PARAMETERS_START(3, 3)
1115 Z_PARAM_LONG(res)
1116 Z_PARAM_LONG(cur)
1117 Z_PARAM_LONG(max)
1118 ZEND_PARSE_PARAMETERS_END();
1119
1120 rl.rlim_cur = cur;
1121 rl.rlim_max = max;
1122
1123 if (setrlimit(res, &rl) == -1) {
1124 POSIX_G(last_error) = errno;
1125 RETURN_FALSE;
1126 }
1127
1128 RETURN_TRUE;
1129 }
1130 /* }}} */
1131
1132 #endif /* HAVE_SETRLIMIT */
1133
1134
1135 /* {{{ Retrieve the error number set by the last posix function which failed. */
PHP_FUNCTION(posix_get_last_error)1136 PHP_FUNCTION(posix_get_last_error)
1137 {
1138 ZEND_PARSE_PARAMETERS_NONE();
1139
1140 RETURN_LONG(POSIX_G(last_error));
1141 }
1142 /* }}} */
1143
1144 /* {{{ Retrieve the system error message associated with the given errno. */
PHP_FUNCTION(posix_strerror)1145 PHP_FUNCTION(posix_strerror)
1146 {
1147 zend_long error;
1148
1149 ZEND_PARSE_PARAMETERS_START(1, 1)
1150 Z_PARAM_LONG(error)
1151 ZEND_PARSE_PARAMETERS_END();
1152
1153 RETURN_STRING(strerror(error));
1154 }
1155 /* }}} */
1156
1157 #endif
1158
1159 #ifdef HAVE_INITGROUPS
1160 /* {{{ Calculate the group access list for the user specified in name. */
PHP_FUNCTION(posix_initgroups)1161 PHP_FUNCTION(posix_initgroups)
1162 {
1163 zend_long basegid;
1164 char *name;
1165 size_t name_len;
1166
1167 ZEND_PARSE_PARAMETERS_START(2, 2)
1168 Z_PARAM_STRING(name, name_len)
1169 Z_PARAM_LONG(basegid)
1170 ZEND_PARSE_PARAMETERS_END();
1171
1172 if (name_len == 0) {
1173 RETURN_FALSE;
1174 }
1175
1176 RETURN_BOOL(!initgroups((const char *)name, basegid));
1177 }
1178 /* }}} */
1179 #endif
1180