awesome-client, socket, lua: make awesome-client into a true REPL
After recieving a command from awesome-client, awesome will send the result of that command in return and awesome-client will print it out. Signed-off-by: Nathan Weizenbaum <nex342@gmail.com> Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
parent
d4daddd076
commit
37f4fbfe39
|
@ -41,6 +41,32 @@
|
|||
#define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
struct sockaddr_un *addr;
|
||||
int csfd;
|
||||
|
||||
/** Initialize the client and server socket connections.
|
||||
* If something goes wrong, preserves errno.
|
||||
* \return 0 if everything worked, 1 otherwise.
|
||||
*/
|
||||
static int
|
||||
sockets_init(void)
|
||||
{
|
||||
return (csfd = socket_getclient()) < 0 ||
|
||||
!(addr = socket_getaddr(getenv("DISPLAY"))) ||
|
||||
connect(csfd, addr, sizeof(struct sockaddr_un)) == -1;
|
||||
}
|
||||
|
||||
|
||||
/** Close the client and server socket connections.
|
||||
*/
|
||||
static void
|
||||
sockets_close(void)
|
||||
{
|
||||
close(csfd);
|
||||
p_delete(&addr);
|
||||
}
|
||||
|
||||
|
||||
/** Send a message to awesome.
|
||||
* \param msg The message.
|
||||
* \param msg_len The message length.
|
||||
|
@ -49,32 +75,42 @@
|
|||
static int
|
||||
send_msg(const char *msg, ssize_t msg_len)
|
||||
{
|
||||
struct sockaddr_un *addr;
|
||||
int csfd, ret_value = EXIT_SUCCESS;
|
||||
csfd = socket_getclient();
|
||||
addr = socket_getaddr(getenv("DISPLAY"));
|
||||
|
||||
if(!addr || csfd < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(sendto(csfd, msg, msg_len, MSG_NOSIGNAL,
|
||||
(const struct sockaddr *) addr, sizeof(struct sockaddr_un)) == -1)
|
||||
if(send(csfd, msg, msg_len, MSG_NOSIGNAL | MSG_EOR) == -1)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
warn("can't write to %s", addr->sun_path);
|
||||
break;
|
||||
warn("can't write to %s", addr->sun_path);
|
||||
break;
|
||||
default:
|
||||
warn("error sending datagram: %s", strerror(errno));
|
||||
}
|
||||
ret_value = errno;
|
||||
warn("error sending packet: %s", strerror(errno));
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
close(csfd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
p_delete(&addr);
|
||||
return ret_value;
|
||||
|
||||
/** Recieve a message from awesome.
|
||||
*/
|
||||
static void
|
||||
recv_msg(void)
|
||||
{
|
||||
ssize_t r;
|
||||
char buf[1024];
|
||||
|
||||
r = recv(csfd, buf, sizeof(buf) - 1, MSG_TRUNC);
|
||||
if (r < 0)
|
||||
{
|
||||
warn("error recieving from UNIX domain socket: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
else if(r > 0)
|
||||
{
|
||||
buf[r] = '\0';
|
||||
puts(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -114,6 +150,12 @@ main(int argc, char **argv)
|
|||
else if(argc > 2)
|
||||
exit_help(EXIT_SUCCESS);
|
||||
|
||||
if (sockets_init())
|
||||
{
|
||||
warn("can't connect to UNIX domain socket: %s", strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(isatty(STDIN_FILENO))
|
||||
{
|
||||
char *display = getenv("DISPLAY");
|
||||
|
@ -126,6 +168,7 @@ main(int argc, char **argv)
|
|||
msg[msg_len] = '\n';
|
||||
msg[msg_len + 1] = '\0';
|
||||
send_msg(msg, msg_len + 2);
|
||||
recv_msg();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -155,6 +198,7 @@ main(int argc, char **argv)
|
|||
p_delete(&msg);
|
||||
}
|
||||
|
||||
sockets_close();
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ socket_getclient(void)
|
|||
{
|
||||
int csfd;
|
||||
|
||||
csfd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
csfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
|
||||
if(csfd < 0)
|
||||
warn("error opening UNIX domain socket: %s", strerror(errno));
|
||||
|
|
108
lua.c
108
lua.c
|
@ -48,6 +48,7 @@
|
|||
#include "event.h"
|
||||
#include "layouts/tile.h"
|
||||
#include "common/socket.h"
|
||||
#include "common/buffer.h"
|
||||
|
||||
extern awesome_t globalconf;
|
||||
|
||||
|
@ -71,6 +72,7 @@ extern const struct luaL_reg awesome_keybinding_meta[];
|
|||
|
||||
static struct sockaddr_un *addr;
|
||||
static ev_io csio = { .fd = -1 };
|
||||
struct ev_io csio2 = { .fd = -1 };
|
||||
|
||||
/** Add a global mouse binding. This binding will be available when you'll
|
||||
* click on root window.
|
||||
|
@ -714,44 +716,130 @@ luaA_parserc(const char *confpatharg)
|
|||
|
||||
/** Parse a command.
|
||||
* \param cmd The buffer to parse.
|
||||
* \return true on succes, false on failure.
|
||||
* \return the number of elements pushed on the stack by the last statement in cmd.
|
||||
* If there's an error, the message is pushed onto the stack and this returns 1.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
luaA_docmd(const char *cmd)
|
||||
{
|
||||
char *p;
|
||||
int newtop, oldtop = lua_gettop(globalconf.L);
|
||||
|
||||
while((p = strchr(cmd, '\n')))
|
||||
{
|
||||
newtop = lua_gettop(globalconf.L);
|
||||
lua_pop(globalconf.L, newtop - oldtop);
|
||||
oldtop = newtop;
|
||||
|
||||
*p = '\0';
|
||||
luaA_dostring(globalconf.L, cmd);
|
||||
if (luaL_dostring(globalconf.L, cmd))
|
||||
{
|
||||
warn("error executing Lua code: %s", lua_tostring(globalconf.L, -1));
|
||||
return 1;
|
||||
}
|
||||
cmd = p + 1;
|
||||
}
|
||||
return lua_gettop(globalconf.L) - oldtop;
|
||||
}
|
||||
|
||||
/** Pushes a Lua array containing the top n elements of the stack.
|
||||
* \param n The number of elements to put in the array.
|
||||
*/
|
||||
static void
|
||||
luaA_array(int n)
|
||||
{
|
||||
int i;
|
||||
lua_createtable(globalconf.L, n, 0);
|
||||
lua_insert(globalconf.L, -n - 1);
|
||||
|
||||
for (i = n; i > 0; i--)
|
||||
lua_rawseti(globalconf.L, -i - 1, i);
|
||||
}
|
||||
|
||||
/** Maps the top n elements of the stack to the result of
|
||||
* applying a function to that element.
|
||||
* \param n The number of elements to map.
|
||||
* \luastack
|
||||
* \lparam The function to map the elements by. This should be
|
||||
* at position -(n + 1).
|
||||
*/
|
||||
static void
|
||||
luaA_map(int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
lua_pushvalue(globalconf.L, -n - 1); /* copy of the function */
|
||||
lua_pushvalue(globalconf.L, -n - 1); /* value to map */
|
||||
lua_pcall(globalconf.L, 1, 1, 0); /* call function */
|
||||
lua_remove(globalconf.L, -n - 1); /* remove old value */
|
||||
}
|
||||
lua_remove(globalconf.L, -n - 1); /* remove function */
|
||||
}
|
||||
|
||||
static void luaA_conn_cleanup(EV_P_ ev_io *w)
|
||||
{
|
||||
ev_ref(EV_DEFAULT_UC);
|
||||
ev_io_stop(EV_DEFAULT_UC_ w);
|
||||
if (close(w->fd))
|
||||
warn("error closing UNIX domain socket: %s", strerror(errno));
|
||||
p_delete(&w);
|
||||
}
|
||||
|
||||
static void
|
||||
luaA_cb(EV_P_ ev_io *w, int revents)
|
||||
{
|
||||
char buf[1024];
|
||||
int r;
|
||||
int r, els;
|
||||
const char *s;
|
||||
size_t len;
|
||||
|
||||
switch(r = recv(w->fd, buf, sizeof(buf)-1, MSG_TRUNC))
|
||||
{
|
||||
case -1:
|
||||
warn("error reading UNIX domain socket: %s", strerror(errno));
|
||||
luaA_cs_cleanup();
|
||||
break;
|
||||
case 0:
|
||||
case 0: /* 0 bytes are only transferred when the connection is closed */
|
||||
luaA_conn_cleanup(EV_DEFAULT_UC_ w);
|
||||
break;
|
||||
default:
|
||||
if(r >= ssizeof(buf))
|
||||
break;
|
||||
buf[r] = '\0';
|
||||
luaA_docmd(buf);
|
||||
lua_getglobal(globalconf.L, "table");
|
||||
lua_getfield(globalconf.L, -1, "concat");
|
||||
lua_remove(globalconf.L, -2); /* remove table */
|
||||
|
||||
lua_getglobal(globalconf.L, "tostring");
|
||||
els = luaA_docmd(buf);
|
||||
luaA_map(els); /* map results to strings */
|
||||
luaA_array(els); /* put strings in an array */
|
||||
|
||||
lua_pushstring(globalconf.L, "\t");
|
||||
lua_pcall(globalconf.L, 2, 1, 0); /* concatenate results with tabs */
|
||||
|
||||
s = lua_tolstring(globalconf.L, -1, &len);
|
||||
|
||||
/* ignore ENOENT because the client doesn't create a socket for non-tty */
|
||||
if (send(w->fd, s, len, 0) == -1 && errno != ENOENT)
|
||||
warn("can't connect to client UNIX domain socket: %s", strerror(errno));
|
||||
|
||||
lua_pop(globalconf.L, 1); /* pop the string */
|
||||
}
|
||||
awesome_refresh(globalconf.connection);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
luaA_conn_cb(EV_P_ ev_io *w, int revents)
|
||||
{
|
||||
ev_io *csio_conn = p_new(ev_io, 1);
|
||||
int csfd = accept(w->fd, NULL, NULL);
|
||||
|
||||
ev_io_init(csio_conn, &luaA_cb, csfd, EV_READ);
|
||||
ev_io_start(EV_DEFAULT_UC_ csio_conn);
|
||||
ev_unref(EV_DEFAULT_UC);
|
||||
}
|
||||
|
||||
void
|
||||
luaA_cs_init(void)
|
||||
{
|
||||
|
@ -774,7 +862,9 @@ luaA_cs_init(void)
|
|||
else
|
||||
warn("error binding UNIX domain socket: %s", strerror(errno));
|
||||
}
|
||||
ev_io_init(&csio, &luaA_cb, csfd, EV_READ);
|
||||
listen(csfd, 10);
|
||||
|
||||
ev_io_init(&csio, &luaA_conn_cb, csfd, EV_READ);
|
||||
ev_io_start(EV_DEFAULT_UC_ &csio);
|
||||
ev_unref(EV_DEFAULT_UC);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue