Exemple #1
0
/* lpty_hasproc
 *
 * Check wether this pty has an active process attached to it.
 *
 * Arguments:
 *	L	Lua State
 *
 * Lua Stack:
 *	1	lpty userdata
 *
 * Lua Returns:
 *	+1	true if there is an active subprocess, false if not.
 */
static int lpty_hasproc(lua_State *L)
{
	lPty *pty = lpty_checkLPty(L, 1);
	int hasit = _lpty_hasrunningchild(pty);
	lua_pushboolean(L, hasit);
	return 1;
}
Exemple #2
0
/* lpty_exitstatus
 *
 * Tries to find the exit status of the last process running in a pty.
 *
 * Arguments:
 *	L	Lua State
 *
 * Lua Stack:
 *	1	lpty userdata
 *
 * Lua Returns:
 *	+1, +2	false, nil if there is an active subprocess
 * 			'exit', code if the previous subprocess exited via exit
 * 			'sig', signum if the previous subprocess was terminated by a signal
 * 			'unk', 0 if we have no information about the previous subprocess
 */
static int lpty_exitstatus(lua_State *L)
{
	lPty *pty = lpty_checkLPty(L, 1);
	if (!_lpty_hasrunningchild(pty) && pty->child != -1) {
		int i;
		for (i = 0; i < EXITSTATUS_BUFSIZ; ++i) {
			if (_lpty_exitstatus_buffer.ecodes[i].child == pty->child) {
				int status = _lpty_exitstatus_buffer.ecodes[i].status;
				if (WIFEXITED(status)) {
					lua_pushliteral(L, "exit");
					lua_pushinteger(L, WEXITSTATUS(status));
				} else if (WIFSIGNALED(status)) {
					lua_pushliteral(L, "sig");
					lua_pushinteger(L, WTERMSIG(status));
				}
				break;
			}
		}
		if (i == EXITSTATUS_BUFSIZ) {
			lua_pushliteral(L, "unk");
			lua_pushinteger(L, 0);
		}
	} else {
		lua_pushboolean(L, 0);
		lua_pushnil(L);
	}
	return 2;
}
Exemple #3
0
/* lpty_gc
 *
 * __gc metamethod for the pty userdata.
 * Kills child process, closes all fd's.
 *
 * Arguments:
 *	L	Lua State
 *
 * Lua Stack:
 *	1	pty object
 */
static int lpty__gc(lua_State *L)
{
	lPty *pty = lpty_toLPty(L, 1);
	/* if here is a running child process, dispose of it.
	 * We do the waitpid() here because this might occur on program shutdown
	 * and thus the SIGCHLD might be delivered after we've terminated. WNOHANG
	 * ensures that we don't bother waiting for a dead child that has already
	 * been reaped, and keeping the signal handler active ensures that no dying
	 * child is left behind. */
	if (_lpty_hasrunningchild(pty)) {
		/* no need to be gentle, this process has been abandoned. */
		kill(pty->child, SIGKILL);
		waitpid(pty->child, NULL, WNOHANG);
	}
	if (pty->m_fd > 0) close(pty->m_fd);
	if (pty->s_fd > 0) close(pty->s_fd);
	return 0;
}
Exemple #4
0
/* lpty_endproc
 *
 * kill the process corresponding to our pty
 *
 * Arguments:
 *	L	Lua State
 *
 * Lua Stack:
 *	1	lpty userdata
 * 	2	(optional) flag wether to send SIGTERM (default, false) or SIGKILL (true)
 *
 * Lua Returns:
 *	-
 * 
 * Note:
 * 	No error is generated if the child process was not active any more.
 */
static int lpty_endproc(lua_State *L)
{
	lPty *pty = lpty_checkLPty(L, 1);
	int sigkill = 0;
	if (lua_gettop(L) > 1) {
		luaL_checktype(L, 2, LUA_TBOOLEAN);
		sigkill = lua_toboolean(L, 2);
	}

	if (_lpty_hasrunningchild(pty)) {
		if (sigkill)
			kill(pty->child, SIGKILL);
		else
			kill(pty->child, SIGTERM);
	}
	
	return 0;
}
Exemple #5
0
/* lpty_startproc
 *
 * start a process with our pty as its controlling terminal.
 *
 * Arguments:
 *	L	Lua State
 *
 * Lua Stack:
 *	1	lpty userdata
 *
 * Lua Returns:
 *	+1	false if the re was already an active subprocess of this pty, true if
 * 		not and we started one.
 * 
 * Note:
 * 	We can not determine wether the command to be spawned in the child process
 * 	was successful.
 */
static int lpty_startproc(lua_State *L)
{
	lPty *pty = lpty_checkLPty(L, 1);
	const char *cmd = luaL_checkstring(L, 2);
	
	/* if pty already has an active child process we just return false and do
	 * nothing */
	if (_lpty_hasrunningchild(pty))
		lua_pushboolean(L, 0);
	else {
		pid_t child;
		int ttyfd = pty->s_fd;

		signal(SIGCHLD, _lpty_sigchld_handler);

		/* now start child process */
		child = fork();
		if (child == 0) {
			/* child process */
			/* fill execvp args array from function arguments */
			int nargs = lua_gettop(L) - 1;
			const char **args = calloc(nargs + 1, sizeof(char*));
			int i;
			args[0] = cmd;
			for (i = 1; i < nargs; ++i)
				args[i] = lua_tostring(L, 2 + i);
			args[nargs] = NULL;
			
			/* prepare child processes standard file handles */
			dup2(ttyfd, 0);
			dup2(ttyfd, 1);
			dup2(ttyfd, 2);

			/* need to create new session id for slave in order for the tty to
			 * become a controlling tty */
			if (setsid() < (pid_t)0) {
				fprintf(stderr, "lpty failed to create new session id.");
				exit(EXIT_FAILURE);
				/* we need to terminate here! */
			}

			/* reset SIGCHLD handler then start our process */
			signal(SIGCHLD, SIG_DFL);
			execvp(cmd, (char* const*)args);

			/* if we ever get here, an error has occurred.
			 * Note: this error will only be visible as output to the pty from the parent side!
			 */
			free(args);
			fprintf(stderr, "error: lpty failed to start child process: %s", strerror(errno));
			exit(EXIT_FAILURE);
			/* we need to terminate here! */
		} else if (child > 0) {
			/* parent process: clean up, store child pid, return success */
			pty->child = child;
			lua_pushboolean(L, 1);
		} else {
			return lpty_error(L, pty->flags.throwerrors, "lpty failed to create child process: %s", strerror(errno));
		}
	} 
	return 1;
}