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