lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

This is really two changes, one which fixes the just-plain-wrong behavior of
the return-value of file:close() when called on a pipe on Linux (and
presumably also other posix platforms) [this is the more important of the
two], and the addition of a second return-value to the API, indicating the
type of exit of the child process.  I wrapped the two into the same patch as
I consider them to be tightly related.

Test case to follow.

>From 661a0822cf5dead4f35779f5d288df9e48e4834f Mon Sep 17 00:00:00 2001
From: David Favro <>
Date: Tue, 18 Jan 2011 13:00:09 -0500
Subject: [PATCH] file:close() return-value is consistent with the manual.

The 5.2-alpha manual says that file:close() [i.e. io.close()], when called on a
file-descriptor that had been opened by io.popen(), returns the process's
exit-status; this was not the behavior under Linux and perhaps other posix
platforms as well: it was returning the return-value of pclose(3), which is
documented as being the same as that returned by wait4(2), which is documented
as being the same as that returned by waitpid(2), which must be interpreted by
the macros in <sys/wait.h>.  This is corrected.

Furthermore, the single return-value doesn't adequately reflect the possible
exit statuses of a child process, which can also exit with a signal: so I have
added an additional return-value indicates if the child process exited via
exit() (in which case it is "e") or signal (in which case it is "s").  This
additional return-value will of course be nil on platforms which don't support
it.  In the case of a signal, the first return-value is the signal number.

Signed-off-by: David Favro <>
 doc/manual.html |    9 +++++++--
 src/liolib.c    |   20 ++++++++++++++++++--
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/doc/manual.html b/doc/manual.html
index c154821..1b608a3 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -8795,8 +8795,13 @@ but that takes an unpredictable amount of time to happen.
 If <code>file</code> was created with <a href="#pdf-io.popen"><code>io.popen</code></a>,
-a successful close returns the exit status of the process.
+a successful close returns the exit status of the process. On platforms that
+support it, there may be a second return value which is either "e" to indicate
+that the child process exited due to an exit() call, or "s" to indicate that the
+child process exited due to a signal, in which case the first return-value was
+the number of the signal which caused the child to terminate, rather than its
+exit status. In other cases, and on platforms which do not support it, the
+second return-value is nil.
diff --git a/src/liolib.c b/src/liolib.c
index 658601a..1c5bf00 100644
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -10,6 +10,10 @@
 #include <stdlib.h>
 #include <string.h>
+#if defined(LUA_USE_LINUX) || defined(__linux__)
+    #include <sys/wait.h>
 #define liolib_c
 #define LUA_LIB
@@ -147,8 +151,20 @@ static int io_pclose (lua_State *L) {
   if (stat == -1)  /* error? */
     return pushresult(L, 0, NULL);
   else {
-    lua_pushinteger(L, stat);
-    return 1;  /* return status */
+    #if defined(LUA_USE_LINUX) || defined(__linux__)
+        /* return:
+         *   process-exit-status or signal-number,
+         *   exit-type ("s" for signal or "e" for exit)
+         */
+        const int exited   = WIFEXITED( stat );
+        const int signaled = WIFSIGNALED( stat );
+        lua_pushinteger( L, exited ? WEXITSTATUS(stat) : (signaled ? WTERMSIG(stat) : 0) );
+        lua_pushstring( L, exited ? "e" : (signaled ? "s" : "") );
+        return 2;
+    #else
+        lua_pushinteger(L, stat);
+        return 1;  /* return status */
+    #endif