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