/* +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Kristian Koehntopp | +----------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include #include "ext/standard/info.h" #include "ext/standard/php_string.h" #include "php_posix.h" #include "posix_arginfo.h" #ifdef HAVE_POSIX #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_MKDEV_H # include #endif #ifdef HAVE_SYS_SYSMACROS_H # include #endif ZEND_DECLARE_MODULE_GLOBALS(posix) static PHP_MINFO_FUNCTION(posix); /* {{{ PHP_MINFO_FUNCTION */ static PHP_MINFO_FUNCTION(posix) { php_info_print_table_start(); php_info_print_table_row(2, "POSIX support", "enabled"); php_info_print_table_end(); } /* }}} */ static PHP_GINIT_FUNCTION(posix) /* {{{ */ { #if defined(COMPILE_DL_POSIX) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif posix_globals->last_error = 0; } /* }}} */ /* {{{ PHP_MINIT_FUNCTION(posix) */ static PHP_MINIT_FUNCTION(posix) { REGISTER_LONG_CONSTANT("POSIX_F_OK", F_OK, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("POSIX_X_OK", X_OK, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("POSIX_W_OK", W_OK, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("POSIX_R_OK", R_OK, CONST_CS | CONST_PERSISTENT); #ifdef S_IFREG REGISTER_LONG_CONSTANT("POSIX_S_IFREG", S_IFREG, CONST_CS | CONST_PERSISTENT); #endif #ifdef S_IFCHR REGISTER_LONG_CONSTANT("POSIX_S_IFCHR", S_IFCHR, CONST_CS | CONST_PERSISTENT); #endif #ifdef S_IFBLK REGISTER_LONG_CONSTANT("POSIX_S_IFBLK", S_IFBLK, CONST_CS | CONST_PERSISTENT); #endif #ifdef S_IFIFO REGISTER_LONG_CONSTANT("POSIX_S_IFIFO", S_IFIFO, CONST_CS | CONST_PERSISTENT); #endif #ifdef S_IFSOCK REGISTER_LONG_CONSTANT("POSIX_S_IFSOCK", S_IFSOCK, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_AS REGISTER_LONG_CONSTANT("POSIX_RLIMIT_AS", RLIMIT_AS, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_CORE REGISTER_LONG_CONSTANT("POSIX_RLIMIT_CORE", RLIMIT_CORE, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_CPU REGISTER_LONG_CONSTANT("POSIX_RLIMIT_CPU", RLIMIT_CPU, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_DATA REGISTER_LONG_CONSTANT("POSIX_RLIMIT_DATA", RLIMIT_DATA, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_FSIZE REGISTER_LONG_CONSTANT("POSIX_RLIMIT_FSIZE", RLIMIT_FSIZE, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_LOCKS REGISTER_LONG_CONSTANT("POSIX_RLIMIT_LOCKS", RLIMIT_LOCKS, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_MEMLOCK REGISTER_LONG_CONSTANT("POSIX_RLIMIT_MEMLOCK", RLIMIT_MEMLOCK, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_MSGQUEUE REGISTER_LONG_CONSTANT("POSIX_RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_NICE REGISTER_LONG_CONSTANT("POSIX_RLIMIT_NICE", RLIMIT_NICE, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_NOFILE REGISTER_LONG_CONSTANT("POSIX_RLIMIT_NOFILE", RLIMIT_NOFILE, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_NPROC REGISTER_LONG_CONSTANT("POSIX_RLIMIT_NPROC", RLIMIT_NPROC, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_RSS REGISTER_LONG_CONSTANT("POSIX_RLIMIT_RSS", RLIMIT_RSS, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_RTPRIO REGISTER_LONG_CONSTANT("POSIX_RLIMIT_RTPRIO", RLIMIT_RTPRIO, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_RTTIME REGISTER_LONG_CONSTANT("POSIX_RLIMIT_RTTIME", RLIMIT_RTTIME, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_SIGPENDING REGISTER_LONG_CONSTANT("POSIX_RLIMIT_SIGPENDING", RLIMIT_SIGPENDING, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_STACK REGISTER_LONG_CONSTANT("POSIX_RLIMIT_STACK", RLIMIT_STACK, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_KQUEUES REGISTER_LONG_CONSTANT("POSIX_RLIMIT_KQUEUES", RLIMIT_KQUEUES, CONST_CS | CONST_PERSISTENT); #endif #ifdef RLIMIT_NPTS REGISTER_LONG_CONSTANT("POSIX_RLIMIT_NPTS", RLIMIT_NPTS, CONST_CS | CONST_PERSISTENT); #endif #ifdef HAVE_SETRLIMIT REGISTER_LONG_CONSTANT("POSIX_RLIMIT_INFINITY", RLIM_INFINITY, CONST_CS | CONST_PERSISTENT); #endif return SUCCESS; } /* }}} */ /* {{{ posix_module_entry */ zend_module_entry posix_module_entry = { STANDARD_MODULE_HEADER, "posix", ext_functions, PHP_MINIT(posix), NULL, NULL, NULL, PHP_MINFO(posix), PHP_POSIX_VERSION, PHP_MODULE_GLOBALS(posix), PHP_GINIT(posix), NULL, NULL, STANDARD_MODULE_PROPERTIES_EX }; /* }}} */ #ifdef COMPILE_DL_POSIX #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE() #endif ZEND_GET_MODULE(posix) #endif #define PHP_POSIX_RETURN_LONG_FUNC(func_name) \ ZEND_PARSE_PARAMETERS_NONE(); \ RETURN_LONG(func_name()); #define PHP_POSIX_SINGLE_ARG_FUNC(func_name) \ zend_long val; \ ZEND_PARSE_PARAMETERS_START(1, 1) \ Z_PARAM_LONG(val) \ ZEND_PARSE_PARAMETERS_END(); \ if (func_name(val) < 0) { \ POSIX_G(last_error) = errno; \ RETURN_FALSE; \ } \ RETURN_TRUE; /* {{{ Send a signal to a process (POSIX.1, 3.3.2) */ PHP_FUNCTION(posix_kill) { zend_long pid, sig; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_LONG(pid) Z_PARAM_LONG(sig) ZEND_PARSE_PARAMETERS_END(); if (kill(pid, sig) < 0) { POSIX_G(last_error) = errno; RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ Get the current process id (POSIX.1, 4.1.1) */ PHP_FUNCTION(posix_getpid) { PHP_POSIX_RETURN_LONG_FUNC(getpid); } /* }}} */ /* {{{ Get the parent process id (POSIX.1, 4.1.1) */ PHP_FUNCTION(posix_getppid) { PHP_POSIX_RETURN_LONG_FUNC(getppid); } /* }}} */ /* {{{ Get the current user id (POSIX.1, 4.2.1) */ PHP_FUNCTION(posix_getuid) { PHP_POSIX_RETURN_LONG_FUNC(getuid); } /* }}} */ /* {{{ Get the current group id (POSIX.1, 4.2.1) */ PHP_FUNCTION(posix_getgid) { PHP_POSIX_RETURN_LONG_FUNC(getgid); } /* }}} */ /* {{{ Get the current effective user id (POSIX.1, 4.2.1) */ PHP_FUNCTION(posix_geteuid) { PHP_POSIX_RETURN_LONG_FUNC(geteuid); } /* }}} */ /* {{{ Get the current effective group id (POSIX.1, 4.2.1) */ PHP_FUNCTION(posix_getegid) { PHP_POSIX_RETURN_LONG_FUNC(getegid); } /* }}} */ /* {{{ Set user id (POSIX.1, 4.2.2) */ PHP_FUNCTION(posix_setuid) { PHP_POSIX_SINGLE_ARG_FUNC(setuid); } /* }}} */ /* {{{ Set group id (POSIX.1, 4.2.2) */ PHP_FUNCTION(posix_setgid) { PHP_POSIX_SINGLE_ARG_FUNC(setgid); } /* }}} */ /* {{{ Set effective user id */ #ifdef HAVE_SETEUID PHP_FUNCTION(posix_seteuid) { PHP_POSIX_SINGLE_ARG_FUNC(seteuid); } #endif /* }}} */ /* {{{ Set effective group id */ #ifdef HAVE_SETEGID PHP_FUNCTION(posix_setegid) { PHP_POSIX_SINGLE_ARG_FUNC(setegid); } #endif /* }}} */ /* {{{ Get supplementary group id's (POSIX.1, 4.2.3) */ #ifdef HAVE_GETGROUPS PHP_FUNCTION(posix_getgroups) { gid_t gidlist[NGROUPS_MAX]; int result; int i; ZEND_PARSE_PARAMETERS_NONE(); if ((result = getgroups(NGROUPS_MAX, gidlist)) < 0) { POSIX_G(last_error) = errno; RETURN_FALSE; } array_init(return_value); for (i=0; iops->label); return 0; } return 1; } /* }}} */ /* {{{ Determine terminal device name (POSIX.1, 4.7.2) */ PHP_FUNCTION(posix_ttyname) { zval *z_fd; char *p; int fd; #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX) zend_long buflen; #endif ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(z_fd) ZEND_PARSE_PARAMETERS_END(); switch (Z_TYPE_P(z_fd)) { case IS_RESOURCE: if (!php_posix_stream_get_fd(z_fd, &fd)) { RETURN_FALSE; } break; default: fd = zval_get_long(z_fd); } #if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX) buflen = sysconf(_SC_TTY_NAME_MAX); if (buflen < 1) { RETURN_FALSE; } p = emalloc(buflen); if (ttyname_r(fd, p, buflen)) { POSIX_G(last_error) = errno; efree(p); RETURN_FALSE; } RETURN_STRING(p); efree(p); #else if (NULL == (p = ttyname(fd))) { POSIX_G(last_error) = errno; RETURN_FALSE; } #endif RETURN_STRING(p); } /* }}} */ /* {{{ Determine if filedesc is a tty (POSIX.1, 4.7.1) */ PHP_FUNCTION(posix_isatty) { zval *z_fd; int fd; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(z_fd) ZEND_PARSE_PARAMETERS_END(); switch (Z_TYPE_P(z_fd)) { case IS_RESOURCE: if (!php_posix_stream_get_fd(z_fd, &fd)) { RETURN_FALSE; } break; default: fd = zval_get_long(z_fd); } if (isatty(fd)) { RETURN_TRUE; } else { RETURN_FALSE; } } /* }}} */ /* POSIX.1, 4.8.1 sysconf() - TODO POSIX.1, 5.7.1 pathconf(), fpathconf() - TODO POSIX.1, 5.1.2 opendir(), readdir(), rewinddir(), closedir() POSIX.1, 5.2.1 chdir() already supported by PHP */ /* {{{ Get working directory pathname (POSIX.1, 5.2.2) */ PHP_FUNCTION(posix_getcwd) { char buffer[MAXPATHLEN]; char *p; ZEND_PARSE_PARAMETERS_NONE(); p = VCWD_GETCWD(buffer, MAXPATHLEN); if (!p) { POSIX_G(last_error) = errno; RETURN_FALSE; } RETURN_STRING(buffer); } /* }}} */ /* POSIX.1, 5.3.x open(), creat(), umask() POSIX.1, 5.4.1 link() already supported by PHP. */ /* {{{ Make a FIFO special file (POSIX.1, 5.4.2) */ #ifdef HAVE_MKFIFO PHP_FUNCTION(posix_mkfifo) { zend_string *path; zend_long mode; int result; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_PATH_STR(path) Z_PARAM_LONG(mode) ZEND_PARSE_PARAMETERS_END(); if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) { RETURN_FALSE; } result = mkfifo(ZSTR_VAL(path), mode); if (result < 0) { POSIX_G(last_error) = errno; RETURN_FALSE; } RETURN_TRUE; } #endif /* }}} */ /* {{{ Make a special or ordinary file (POSIX.1) */ #ifdef HAVE_MKNOD PHP_FUNCTION(posix_mknod) { zend_string *path; zend_long mode; zend_long major = 0, minor = 0; int result; dev_t php_dev = 0; ZEND_PARSE_PARAMETERS_START(2, 4) Z_PARAM_PATH_STR(path) Z_PARAM_LONG(mode) Z_PARAM_OPTIONAL Z_PARAM_LONG(major) Z_PARAM_LONG(minor) ZEND_PARSE_PARAMETERS_END(); if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) { RETURN_FALSE; } if ((mode & S_IFCHR) || (mode & S_IFBLK)) { if (major == 0) { zend_argument_value_error(3, "cannot be 0 for the POSIX_S_IFCHR and POSIX_S_IFBLK modes"); RETURN_THROWS(); } else { #if defined(HAVE_MAKEDEV) || defined(makedev) php_dev = makedev(major, minor); #else php_error_docref(NULL, E_WARNING, "Cannot create a block or character device, creating a normal file instead"); #endif } } result = mknod(ZSTR_VAL(path), mode, php_dev); if (result < 0) { POSIX_G(last_error) = errno; RETURN_FALSE; } RETURN_TRUE; } #endif /* }}} */ /* Takes a pointer to posix group and a pointer to an already initialized ZVAL * array container and fills the array with the posix group member data. */ int php_posix_group_to_array(struct group *g, zval *array_group) /* {{{ */ { zval array_members; int count; if (NULL == g) return 0; if (array_group == NULL || Z_TYPE_P(array_group) != IS_ARRAY) return 0; array_init(&array_members); add_assoc_string(array_group, "name", g->gr_name); if (g->gr_passwd) { add_assoc_string(array_group, "passwd", g->gr_passwd); } else { add_assoc_null(array_group, "passwd"); } for (count = 0;; count++) { /* gr_mem entries may be misaligned on macos. */ char *gr_mem; memcpy(&gr_mem, &g->gr_mem[count], sizeof(char *)); if (!gr_mem) { break; } add_next_index_string(&array_members, gr_mem); } zend_hash_str_update(Z_ARRVAL_P(array_group), "members", sizeof("members")-1, &array_members); add_assoc_long(array_group, "gid", g->gr_gid); return 1; } /* }}} */ /* POSIX.1, 5.5.1 unlink() POSIX.1, 5.5.2 rmdir() POSIX.1, 5.5.3 rename() POSIX.1, 5.6.x stat(), chmod(), utime() already supported by PHP. */ /* {{{ Determine accessibility of a file (POSIX.1 5.6.3) */ PHP_FUNCTION(posix_access) { zend_long mode = 0; size_t filename_len, ret; char *filename, *path; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_PATH(filename, filename_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(mode) ZEND_PARSE_PARAMETERS_END(); path = expand_filepath(filename, NULL); if (!path) { POSIX_G(last_error) = EIO; RETURN_FALSE; } if (php_check_open_basedir_ex(path, 0)) { efree(path); POSIX_G(last_error) = EPERM; RETURN_FALSE; } ret = access(path, mode); efree(path); if (ret) { POSIX_G(last_error) = errno; RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* POSIX.1, 6.x most I/O functions already supported by PHP. POSIX.1, 7.x tty functions, TODO POSIX.1, 8.x interactions with other C language functions POSIX.1, 9.x system database access */ /* {{{ Group database access (POSIX.1, 9.2.1) */ PHP_FUNCTION(posix_getgrnam) { char *name; struct group *g; size_t name_len; #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) struct group gbuf; long buflen; char *buf; #endif ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) buflen = sysconf(_SC_GETGR_R_SIZE_MAX); if (buflen < 1) { RETURN_FALSE; } buf = emalloc(buflen); try_again: g = &gbuf; if (getgrnam_r(name, g, buf, buflen, &g) || g == NULL) { if (errno == ERANGE) { buflen *= 2; buf = erealloc(buf, buflen); goto try_again; } POSIX_G(last_error) = errno; efree(buf); RETURN_FALSE; } #else if (NULL == (g = getgrnam(name))) { POSIX_G(last_error) = errno; RETURN_FALSE; } #endif array_init(return_value); if (!php_posix_group_to_array(g, return_value)) { zend_array_destroy(Z_ARR_P(return_value)); php_error_docref(NULL, E_WARNING, "Unable to convert posix group to array"); RETVAL_FALSE; } #if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX) efree(buf); #endif } /* }}} */ /* {{{ Group database access (POSIX.1, 9.2.1) */ PHP_FUNCTION(posix_getgrgid) { zend_long gid; #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX) int ret; struct group _g; struct group *retgrptr = NULL; long grbuflen; char *grbuf; #endif struct group *g; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(gid) ZEND_PARSE_PARAMETERS_END(); #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX) grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX); if (grbuflen < 1) { RETURN_FALSE; } grbuf = emalloc(grbuflen); try_again: ret = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr); if (ret || retgrptr == NULL) { if (errno == ERANGE) { grbuflen *= 2; grbuf = erealloc(grbuf, grbuflen); goto try_again; } POSIX_G(last_error) = ret; efree(grbuf); RETURN_FALSE; } g = &_g; #else if (NULL == (g = getgrgid(gid))) { POSIX_G(last_error) = errno; RETURN_FALSE; } #endif array_init(return_value); if (!php_posix_group_to_array(g, return_value)) { zend_array_destroy(Z_ARR_P(return_value)); php_error_docref(NULL, E_WARNING, "Unable to convert posix group struct to array"); RETVAL_FALSE; } #if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX) efree(grbuf); #endif } /* }}} */ int php_posix_passwd_to_array(struct passwd *pw, zval *return_value) /* {{{ */ { if (NULL == pw) return 0; if (NULL == return_value || Z_TYPE_P(return_value) != IS_ARRAY) return 0; add_assoc_string(return_value, "name", pw->pw_name); add_assoc_string(return_value, "passwd", pw->pw_passwd); add_assoc_long (return_value, "uid", pw->pw_uid); add_assoc_long (return_value, "gid", pw->pw_gid); add_assoc_string(return_value, "gecos", pw->pw_gecos); add_assoc_string(return_value, "dir", pw->pw_dir); add_assoc_string(return_value, "shell", pw->pw_shell); return 1; } /* }}} */ /* {{{ User database access (POSIX.1, 9.2.2) */ PHP_FUNCTION(posix_getpwnam) { struct passwd *pw; char *name; size_t name_len; #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R) struct passwd pwbuf; long buflen; char *buf; #endif ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(name, name_len) ZEND_PARSE_PARAMETERS_END(); #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R) buflen = sysconf(_SC_GETPW_R_SIZE_MAX); if (buflen < 1) { RETURN_FALSE; } buf = emalloc(buflen); pw = &pwbuf; try_again: if (getpwnam_r(name, pw, buf, buflen, &pw) || pw == NULL) { if (errno == ERANGE) { buflen *= 2; buf = erealloc(buf, buflen); goto try_again; } efree(buf); POSIX_G(last_error) = errno; RETURN_FALSE; } #else if (NULL == (pw = getpwnam(name))) { POSIX_G(last_error) = errno; RETURN_FALSE; } #endif array_init(return_value); if (!php_posix_passwd_to_array(pw, return_value)) { zend_array_destroy(Z_ARR_P(return_value)); php_error_docref(NULL, E_WARNING, "Unable to convert posix passwd struct to array"); RETVAL_FALSE; } #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R) efree(buf); #endif } /* }}} */ /* {{{ User database access (POSIX.1, 9.2.2) */ PHP_FUNCTION(posix_getpwuid) { zend_long uid; #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R) struct passwd _pw; struct passwd *retpwptr = NULL; long pwbuflen; char *pwbuf; int ret; #endif struct passwd *pw; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(uid) ZEND_PARSE_PARAMETERS_END(); #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R) pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); if (pwbuflen < 1) { RETURN_FALSE; } pwbuf = emalloc(pwbuflen); try_again: ret = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr); if (ret || retpwptr == NULL) { if (errno == ERANGE) { pwbuflen *= 2; pwbuf = erealloc(pwbuf, pwbuflen); goto try_again; } POSIX_G(last_error) = ret; efree(pwbuf); RETURN_FALSE; } pw = &_pw; #else if (NULL == (pw = getpwuid(uid))) { POSIX_G(last_error) = errno; RETURN_FALSE; } #endif array_init(return_value); if (!php_posix_passwd_to_array(pw, return_value)) { zend_array_destroy(Z_ARR_P(return_value)); php_error_docref(NULL, E_WARNING, "Unable to convert posix passwd struct to array"); RETVAL_FALSE; } #if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R) efree(pwbuf); #endif } /* }}} */ #ifdef HAVE_GETRLIMIT #define UNLIMITED_STRING "unlimited" /* {{{ posix_addlimit */ static int posix_addlimit(int limit, const char *name, zval *return_value) { int result; struct rlimit rl; char hard[80]; char soft[80]; snprintf(hard, 80, "hard %s", name); snprintf(soft, 80, "soft %s", name); result = getrlimit(limit, &rl); if (result < 0) { POSIX_G(last_error) = errno; return FAILURE; } if (rl.rlim_cur == RLIM_INFINITY) { add_assoc_stringl(return_value, soft, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1); } else { add_assoc_long(return_value, soft, rl.rlim_cur); } if (rl.rlim_max == RLIM_INFINITY) { add_assoc_stringl(return_value, hard, UNLIMITED_STRING, sizeof(UNLIMITED_STRING)-1); } else { add_assoc_long(return_value, hard, rl.rlim_max); } return SUCCESS; } /* }}} */ /* {{{ limits[] */ static const struct limitlist { int limit; const char *name; } limits[] = { #ifdef RLIMIT_CORE { RLIMIT_CORE, "core" }, #endif #ifdef RLIMIT_DATA { RLIMIT_DATA, "data" }, #endif #ifdef RLIMIT_STACK { RLIMIT_STACK, "stack" }, #endif #ifdef RLIMIT_VMEM { RLIMIT_VMEM, "virtualmem" }, #endif #ifdef RLIMIT_AS { RLIMIT_AS, "totalmem" }, #endif #ifdef RLIMIT_RSS { RLIMIT_RSS, "rss" }, #endif #ifdef RLIMIT_NPROC { RLIMIT_NPROC, "maxproc" }, #endif #ifdef RLIMIT_MEMLOCK { RLIMIT_MEMLOCK, "memlock" }, #endif #ifdef RLIMIT_CPU { RLIMIT_CPU, "cpu" }, #endif #ifdef RLIMIT_FSIZE { RLIMIT_FSIZE, "filesize" }, #endif #ifdef RLIMIT_NOFILE { RLIMIT_NOFILE, "openfiles" }, #endif #ifdef RLIMIT_OFILE { RLIMIT_OFILE, "openfiles" }, #endif #ifdef RLIMIT_KQUEUES { RLIMIT_KQUEUES, "kqueues" }, #endif #ifdef RLIMIT_NPTS { RLIMIT_NPTS, "npts" }, #endif { 0, NULL } }; /* }}} */ /* {{{ Get system resource consumption limits (This is not a POSIX function, but a BSDism and a SVR4ism. We compile conditionally) */ PHP_FUNCTION(posix_getrlimit) { const struct limitlist *l = NULL; ZEND_PARSE_PARAMETERS_NONE(); array_init(return_value); for (l=limits; l->name; l++) { if (posix_addlimit(l->limit, l->name, return_value) == FAILURE) { zend_array_destroy(Z_ARR_P(return_value)); RETURN_FALSE; } } } /* }}} */ #endif /* HAVE_GETRLIMIT */ #ifdef HAVE_SETRLIMIT /* {{{ Set system resource consumption limits (POSIX.1-2001) */ PHP_FUNCTION(posix_setrlimit) { struct rlimit rl; zend_long res, cur, max; ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_LONG(res) Z_PARAM_LONG(cur) Z_PARAM_LONG(max) ZEND_PARSE_PARAMETERS_END(); rl.rlim_cur = cur; rl.rlim_max = max; if (setrlimit(res, &rl) == -1) { POSIX_G(last_error) = errno; RETURN_FALSE; } RETURN_TRUE; } /* }}} */ #endif /* HAVE_SETRLIMIT */ /* {{{ Retrieve the error number set by the last posix function which failed. */ PHP_FUNCTION(posix_get_last_error) { ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(POSIX_G(last_error)); } /* }}} */ /* {{{ Retrieve the system error message associated with the given errno. */ PHP_FUNCTION(posix_strerror) { zend_long error; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(error) ZEND_PARSE_PARAMETERS_END(); RETURN_STRING(strerror(error)); } /* }}} */ #endif #ifdef HAVE_INITGROUPS /* {{{ Calculate the group access list for the user specified in name. */ PHP_FUNCTION(posix_initgroups) { zend_long basegid; char *name; size_t name_len; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STRING(name, name_len) Z_PARAM_LONG(basegid) ZEND_PARSE_PARAMETERS_END(); if (name_len == 0) { RETURN_FALSE; } RETURN_BOOL(!initgroups((const char *)name, basegid)); } /* }}} */ #endif