2 * pty.c - pty bindings for Lua
3 * $Id: pty.c,v 1.21 2005/04/04 13:56:37 den Exp $
5 * This file was derived in part from DragonFly BSD's
6 * src/usr.bin/script/script.c, which contains the following license:
9 * Copyright (c) 1980, 1992, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 #include <sys/types.h>
53 #include "lua50/lua.h"
54 #include "lua50/lauxlib.h"
55 #include "lua50/lualib.h"
58 #define WEXIT_TYPE int
60 #define WEXIT_TYPE union wait
68 #define PTY_TIMEOUT -1
71 LUA_API int luaopen_lpty(lua_State *);
76 * Given the names of two global variables, the first a regular
77 * 'Class' table, and the second a metatable which will be attached
78 * to all object 'instances':
79 * - add an __index property to the metatable that redirects
80 * all accesses on the instance to the class table;
81 * - add a __metatable propery to the metatable, to hide it.
84 lua_set_instance_handler(lua_State *L,
85 const char *table_name, const char *metatable_name)
87 int metatable_idx, methods_idx;
89 lua_pushstring(L, table_name); /* name of our 'class' table */
90 lua_gettable(L, LUA_GLOBALSINDEX); /* get it from globals */
91 methods_idx = lua_gettop(L); /* Find its position on the stack */
93 lua_pushstring(L, metatable_name); /* name of our metatable */
94 lua_gettable(L, LUA_GLOBALSINDEX); /* get it from globals */
95 metatable_idx = lua_gettop(L); /* Find its position on the stack */
98 * Add __index event to metatable (metatable.__index = methods).
99 * This lets the Lua script refer to the methods by indexing
100 * the instance variable like so: x:y(z).
102 lua_pushliteral(L, "__index");
103 lua_pushvalue(L, methods_idx);
104 lua_settable(L, metatable_idx);
106 lua_pushliteral(L, "__metatable"); /* hide metatable */
107 lua_pushvalue(L, methods_idx);
108 lua_settable(L, metatable_idx); /* metatable.__metatable = methods */
113 /*** STACK ACCESS ***/
115 static struct lua_pty *
116 lua_check_pty(lua_State *L, int ch_index)
118 luaL_checktype(L, ch_index, LUA_TUSERDATA);
119 lua_getmetatable(L, ch_index);
120 lua_pushliteral(L, "PtyMeta");
121 lua_rawget(L, LUA_GLOBALSINDEX);
122 if (!lua_rawequal(L, -1, -2))
123 luaL_typerror(L, ch_index, "Pty");
125 return((struct lua_pty *)lua_unboxpointer(L, ch_index));
128 static struct lua_pty *
129 lua_push_pty(lua_State *L, struct lua_pty *x)
131 lua_boxpointer(L, x);
132 lua_pushliteral(L, "PtyMeta");
133 lua_gettable(L, LUA_GLOBALSINDEX);
134 lua_setmetatable(L, -2);
138 /*** CONSTRUCTOR/DESTRUCTOR ***/
141 lua_pty_open(lua_State *L)
146 pty = malloc(sizeof(struct lua_pty));
149 lua_pushnumber(L, ENOMEM);
153 if (openpty(&master, &slave, NULL, NULL, NULL) == -1) {
155 lua_pushnumber(L, errno);
160 if (pty->child < 0) {
162 lua_pushnumber(L, errno);
165 if (pty->child == 0) {
166 const char *shell = "/bin/sh";
170 execl(shell, shell, "-c", luaL_checkstring(L, 1), NULL);
171 /* if we made it here, an error occurred! */
176 * Convert the file descriptor into a stream, or die trying.
178 if ((pty->stream = fdopen(master, "r+")) == NULL) {
181 kill(pty->child, SIGTERM);
182 if (waitpid(pty->child, (int *)&status, 0) != pty->child) {
184 lua_pushnumber(L, errno);
188 lua_pushnumber(L, errno);
192 lua_push_pty(L, pty);
196 /******* METHODS *******/
199 lua_pty_readline(lua_State *L)
207 struct timeval *tvp = NULL;
209 pty = lua_check_pty(L, 1);
210 if (lua_isnumber(L, 2)) {
211 msec = lua_tonumber(L, 2);
217 FD_SET(fileno(pty->stream), &rfd);
219 tv.tv_sec = msec / 1000;
220 tv.tv_usec = (msec % 1000) * 1000;
222 n = select(fileno(pty->stream) + 1, &rfd, 0, 0, tvp);
225 lua_pushnumber(L, errno);
227 } else if (n > 0 && FD_ISSET(fileno(pty->stream), &rfd)) {
228 if (fgets(line, sizeof(line) - 1, pty->stream) == NULL) {
230 if (feof(pty->stream))
231 lua_pushnumber(L, PTY_EOF);
233 lua_pushnumber(L, errno);
237 while (len > 0 && (line[len - 1] == '\n' ||
238 line[len - 1] == '\r')) {
241 lua_pushstring(L, line);
246 lua_pushnumber(L, PTY_TIMEOUT);
252 lua_pty_write(lua_State *L)
257 pty = lua_check_pty(L, 1);
258 string = luaL_checkstring(L, 2);
261 fwrite(string, 1, strlen(string), pty->stream);
266 lua_pty_flush(lua_State *L)
271 pty = lua_check_pty(L, 1);
273 result = fflush(pty->stream);
274 lua_pushnumber(L, result);
279 lua_pty_close(lua_State *L)
285 pty = lua_check_pty(L, 1);
287 if (pty->stream == NULL) {
289 * It's already been closed.
290 * Don't try to close it again.
292 lua_pushnumber(L, -1);
299 if (waitpid(pty->child, (int *)&status, 0) != pty->child) {
301 lua_pushnumber(L, errno);
305 if (WIFEXITED(status)) {
306 e = WEXITSTATUS(status);
307 } else if (WIFSIGNALED(status)) {
308 e = WTERMSIG(status);
310 /* Only happens when system is out of file descriptors */
314 lua_pushnumber(L, e);
319 lua_pty_signal(lua_State *L)
324 pty = lua_check_pty(L, 1);
325 signo = luaL_checkint(L, 2);
326 result = kill(pty->child, signo);
327 lua_pushnumber(L, result);
332 /**** Binding Tables ****/
334 const luaL_reg pty_methods[] = {
335 {"open", lua_pty_open },
336 {"readline", lua_pty_readline },
337 {"write", lua_pty_write },
338 {"flush", lua_pty_flush },
339 {"close", lua_pty_close },
340 {"signal", lua_pty_signal },
344 const luaL_reg pty_meta_methods[] = {
345 {"__gc", lua_pty_close },
352 luaopen_lpty(lua_State *L)
356 luaL_openlib(L, "Pty", pty_methods, 0); /* fill methods table */
357 luaL_openlib(L, "PtyMeta", pty_meta_methods, 0); /* fill metatable */
360 lua_set_instance_handler(L, "Pty", "PtyMeta");
363 * Add some symbolic constants.
365 methods_idx = lua_gettop(L);
367 lua_pushliteral(L, "TIMEOUT");
368 lua_pushnumber(L, PTY_TIMEOUT);
369 lua_settable(L, methods_idx);
371 lua_pushliteral(L, "EOF");
372 lua_pushnumber(L, PTY_EOF);
373 lua_settable(L, methods_idx);
375 lua_pushliteral(L, "SIGTERM");
376 lua_pushnumber(L, SIGTERM);
377 lua_settable(L, methods_idx);