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