]> granicus.if.org Git - php/commitdiff
Fix bug #52173 (ext/pcntl doesn't store/report errors) (patch
authorArnaud Le Blanc <lbarnaud@php.net>
Mon, 1 Nov 2010 20:10:17 +0000 (20:10 +0000)
committerArnaud Le Blanc <lbarnaud@php.net>
Mon, 1 Nov 2010 20:10:17 +0000 (20:10 +0000)
by nick dot telford at gmail dot com)

ext/pcntl/pcntl.c
ext/pcntl/php_pcntl.h
ext/pcntl/tests/pcntl_get_last_error.phpt [new file with mode: 0644]

index 1594fb1fa7c5f0ea381b15e36c6a6a5d92332936..7c5dc0ea06788e8e326df442f3542d624ece2ca0 100755 (executable)
@@ -44,6 +44,8 @@
 #include <sys/resource.h>
 #endif
 
+#include <errno.h>
+
 ZEND_DECLARE_MODULE_GLOBALS(pcntl)
 static PHP_GINIT_FUNCTION(pcntl);
 
@@ -134,6 +136,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
        ZEND_ARG_INFO(0, process_identifier)
 ZEND_END_ARG_INFO()
 #endif
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
+        ZEND_ARG_INFO(0, errno)
+ZEND_END_ARG_INFO()
 /* }}} */
 
 const zend_function_entry pcntl_functions[] = {
@@ -150,6 +156,9 @@ const zend_function_entry pcntl_functions[] = {
        PHP_FE(pcntl_wstopsig,          arginfo_pcntl_wstopsig)
        PHP_FE(pcntl_exec,                      arginfo_pcntl_exec)
        PHP_FE(pcntl_alarm,                     arginfo_pcntl_alarm)
+       PHP_FE(pcntl_get_last_error,    arginfo_pcntl_void)
+       PHP_FALIAS(pcntl_errno, pcntl_get_last_error,   NULL)
+       PHP_FE(pcntl_strerror,          arginfo_pcntl_strerror)
 #ifdef HAVE_GETPRIORITY
        PHP_FE(pcntl_getpriority,       arginfo_pcntl_getpriority)
 #endif
@@ -407,6 +416,73 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
        /* }}} */
 }
 
+static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
+{
+#ifdef EINTR
+       REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
+#endif
+#ifdef ECHILD
+       REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
+#endif
+#ifdef EINVAL
+       REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
+#endif
+#ifdef EAGAIN
+       REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
+#endif
+#ifdef ESRCH
+       REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
+#endif
+#ifdef EACCES
+       REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
+#endif
+#ifdef EPERM
+       REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
+#endif
+#ifdef ENOMEM
+       REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
+#endif
+#ifdef E2BIG
+       REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
+#endif
+#ifdef EFAULT
+       REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
+#endif
+#ifdef EIO
+       REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
+#endif
+#ifdef EISDIR
+       REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
+#endif
+#ifdef ELIBBAD
+       REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
+#endif
+#ifdef ELOOP
+       REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
+#endif
+#ifdef EMFILE
+       REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
+#endif
+#ifdef ENAMETOOLONG
+       REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
+#endif
+#ifdef ENFILE
+       REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
+#endif
+#ifdef ENOENT
+       REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
+#endif
+#ifdef ENOEXEC
+       REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
+#endif
+#ifdef ENOTDIR
+       REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
+#endif
+#ifdef ETXTBSY
+       REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
+#endif
+}
+
 static PHP_GINIT_FUNCTION(pcntl)
 { 
        memset(pcntl_globals, 0, sizeof(*pcntl_globals));
@@ -422,6 +498,7 @@ PHP_RINIT_FUNCTION(pcntl)
 PHP_MINIT_FUNCTION(pcntl)
 {
        php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
+       php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
        php_add_tick_function(pcntl_signal_dispatch);
 
        return SUCCESS;
@@ -467,6 +544,7 @@ PHP_FUNCTION(pcntl_fork)
 
        id = fork();
        if (id == -1) {
+               PCNTL_G(last_error) = errno;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
        }
        
@@ -505,6 +583,10 @@ PHP_FUNCTION(pcntl_waitpid)
 
        child_id = waitpid((pid_t) pid, &status, options);
 
+       if (child_id < 0) {
+               PCNTL_G(last_error) = errno;
+       }
+
        Z_LVAL_P(z_status) = status;
 
        RETURN_LONG((long) child_id);
@@ -536,6 +618,10 @@ PHP_FUNCTION(pcntl_wait)
 #else
        child_id = wait(&status);
 #endif
+       if (child_id < 0) {
+               PCNTL_G(last_error) = errno;
+       }
+
        Z_LVAL_P(z_status) = status;
 
        RETURN_LONG((long) child_id);
@@ -729,6 +815,7 @@ PHP_FUNCTION(pcntl_exec)
                *(pair) = NULL;
 
                if (execve(path, argv, envp) == -1) {
+                       PCNTL_G(last_error) = errno;
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
                }
        
@@ -738,6 +825,7 @@ PHP_FUNCTION(pcntl_exec)
        } else {
 
                if (execv(path, argv) == -1) {
+                       PCNTL_G(last_error) = errno;
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
                }
        }
@@ -780,6 +868,7 @@ PHP_FUNCTION(pcntl_signal)
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
                }
                if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
+                       PCNTL_G(last_error) = errno;
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
                        RETURN_FALSE;
                }
@@ -787,6 +876,7 @@ PHP_FUNCTION(pcntl_signal)
        }
        
        if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
+               PCNTL_G(last_error) = EINVAL;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
                efree(func_name);
                RETURN_FALSE;
@@ -798,6 +888,7 @@ PHP_FUNCTION(pcntl_signal)
        if (dest_handle) zval_add_ref(dest_handle);
        
        if (php_signal(signo, pcntl_signal_handler, (int) restart_syscalls) == SIG_ERR) {
+               PCNTL_G(last_error) = errno;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
                RETURN_FALSE;
        }
@@ -829,6 +920,7 @@ PHP_FUNCTION(pcntl_sigprocmask)
        }
 
        if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
+               PCNTL_G(last_error) = errno;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
                RETURN_FALSE;
        }
@@ -842,6 +934,7 @@ PHP_FUNCTION(pcntl_sigprocmask)
                }
                signo = Z_LVAL_PP(user_signo);
                if (sigaddset(&set, signo) != 0) {
+                       PCNTL_G(last_error) = errno;
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
                        RETURN_FALSE;
                }
@@ -849,6 +942,7 @@ PHP_FUNCTION(pcntl_sigprocmask)
        }
 
        if (sigprocmask(how, &set, &oldset) != 0) {
+               PCNTL_G(last_error) = errno;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
                RETURN_FALSE;
        }
@@ -895,6 +989,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
        }
 
        if (sigemptyset(&set) != 0) {
+               PCNTL_G(last_error) = errno;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
                RETURN_FALSE;
        }
@@ -908,6 +1003,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
                }
                signo = Z_LVAL_PP(user_signo);
                if (sigaddset(&set, signo) != 0) {
+                       PCNTL_G(last_error) = errno;
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
                        RETURN_FALSE;
                }
@@ -922,6 +1018,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
                signo = sigwaitinfo(&set, &siginfo);
        }
        if (signo == -1 && errno != EAGAIN) {
+               PCNTL_G(last_error) = errno;
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
        }
 
@@ -1015,6 +1112,7 @@ PHP_FUNCTION(pcntl_getpriority)
        pri = getpriority(who, pid);
 
        if (errno) {
+               PCNTL_G(last_error) = errno;
                switch (errno) {
                        case ESRCH:
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
@@ -1048,6 +1146,7 @@ PHP_FUNCTION(pcntl_setpriority)
        }
 
        if (setpriority(who, pid, pri)) {
+               PCNTL_G(last_error) = errno;
                switch (errno) {
                        case ESRCH:
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
@@ -1073,6 +1172,28 @@ PHP_FUNCTION(pcntl_setpriority)
 /* }}} */
 #endif
 
+/* {{{ proto int pcntl_get_last_error(void)
+   Retrieve the error number set by the last pcntl function which failed. */
+PHP_FUNCTION(pcntl_get_last_error)
+{
+        RETURN_LONG(PCNTL_G(last_error));
+}
+/* }}} */
+
+/* {{{ proto string pcntl_strerror(int errno)
+   Retrieve the system error message associated with the given errno. */
+PHP_FUNCTION(pcntl_strerror)
+{
+        long error;
+
+        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) {
+                RETURN_FALSE;
+        }
+
+        RETURN_STRING(strerror(error), 1);
+}
+/* }}} */
+
 /* Our custom signal handler that calls the appropriate php_function */
 static void pcntl_signal_handler(int signo)
 {
index 35afb2cc3c38df2d7b1c6a24e7986a6487ca0f10..6db18633c8555df958a13cf198bbe23f6e439fc7 100644 (file)
@@ -42,6 +42,8 @@ PHP_FUNCTION(pcntl_wtermsig);
 PHP_FUNCTION(pcntl_wstopsig);
 PHP_FUNCTION(pcntl_signal);
 PHP_FUNCTION(pcntl_signal_dispatch);
+PHP_FUNCTION(pcntl_get_last_error);
+PHP_FUNCTION(pcntl_strerror);
 #ifdef HAVE_SIGPROCMASK
 PHP_FUNCTION(pcntl_sigprocmask);
 #endif
@@ -66,6 +68,7 @@ ZEND_BEGIN_MODULE_GLOBALS(pcntl)
        HashTable php_signal_table;
        int processing_signal_queue;
        struct php_pcntl_pending_signal *head, *tail, *spares;
+       int last_error;
 ZEND_END_MODULE_GLOBALS(pcntl)
 
 #ifdef ZTS
@@ -74,6 +77,8 @@ ZEND_END_MODULE_GLOBALS(pcntl)
 #define PCNTL_G(v)     (pcntl_globals.v)
 #endif
 
+#define REGISTER_PCNTL_ERRNO_CONSTANT(name) REGISTER_LONG_CONSTANT("PCNTL_" #name, name, CONST_CS | CONST_PERSISTENT)
+
 #endif /* PHP_PCNTL_H */
 
 
diff --git a/ext/pcntl/tests/pcntl_get_last_error.phpt b/ext/pcntl/tests/pcntl_get_last_error.phpt
new file mode 100644 (file)
index 0000000..4ed66c9
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Test pcntl_get_last_error()
+--SKIPIF--
+<?php
+       if (!extension_loaded("pcntl")) print "skip"; 
+?>
+--FILE--
+<?php 
+var_dump(pcntl_get_last_error());
+$pid = pcntl_wait($status);
+var_dump($pid);
+var_dump(pcntl_get_last_error() == PCNTL_ECHILD);
+?>
+--EXPECT--
+int(0)
+int(-1)
+bool(true)