201 lines
4.7 KiB
C
201 lines
4.7 KiB
C
#include "e_system.h"
|
|
|
|
typedef struct
|
|
{
|
|
void (*func) (void *data, const char *params);
|
|
void *data;
|
|
} Handler;
|
|
|
|
static Eina_Hash *_cmd_handlers = NULL;
|
|
static Ecore_Fd_Handler *_fdh_in = NULL;
|
|
|
|
//// note: commands are of the form:
|
|
// [ 24 bytes] command string including nul byte terminator and 0 padding
|
|
// [ 4 bytes] payload size (max size 2gb)
|
|
// [ N bytes] payload data (0 or more)...
|
|
|
|
typedef struct
|
|
{
|
|
char cmd[24];
|
|
int size;
|
|
} Message_Head;
|
|
|
|
static int fd_null = -1, fd_supress = -1;
|
|
|
|
static void
|
|
_stdout_off(void)
|
|
{
|
|
fflush(stdout);
|
|
fd_supress = dup(1);
|
|
if (fd_null == -1) fd_null = open("/dev/null", O_WRONLY);
|
|
if (fd_null != -1) dup2(fd_null, 1);
|
|
}
|
|
|
|
static void
|
|
_stdout_on(void)
|
|
{
|
|
fflush(stdout);
|
|
dup2(fd_supress, 1);
|
|
close(fd_supress);
|
|
close(fd_null);
|
|
fd_supress = -1;
|
|
fd_null = -1;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_cb_stdio_in_read(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
|
|
{
|
|
Handler *h;
|
|
Message_Head head;
|
|
ssize_t ret;
|
|
|
|
errno = 0;
|
|
ret = read(0, &head, sizeof(head));
|
|
if (ret < 1)
|
|
{
|
|
int e = errno;
|
|
if ((e == EIO) || (e == EBADF) || (e == EPIPE) ||
|
|
(e == EINVAL) || (e == ENOSPC) ||
|
|
(!((e == EAGAIN) || (e == EINTR))))
|
|
{
|
|
ecore_main_loop_quit();
|
|
goto done;
|
|
}
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
char *buf;
|
|
|
|
if (head.size < 0)
|
|
{
|
|
ERR("Invalid message payload size (less than 0)\n");
|
|
abort();
|
|
}
|
|
if (head.size > (1024 * 1024))
|
|
{
|
|
ERR("Invalid message payload size (more than 1M)\n");
|
|
abort();
|
|
}
|
|
buf = NULL;
|
|
if (head.size > 0)
|
|
{
|
|
buf = malloc(head.size);
|
|
if (!buf)
|
|
{
|
|
ERR("Out of memory for message of size %i bytes\n", head.size);
|
|
abort();
|
|
}
|
|
ret = read(0, buf, head.size);
|
|
if (ret != head.size)
|
|
{
|
|
ERR("Cannot read full message payload of %i bytes\n", head.size);
|
|
abort();
|
|
}
|
|
}
|
|
h = eina_hash_find(_cmd_handlers, head.cmd);
|
|
if (h)
|
|
{
|
|
if ((!buf) || ((buf) && (buf[head.size - 1] == '\0')))
|
|
h->func(h->data, buf);
|
|
}
|
|
free(buf);
|
|
}
|
|
done:
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
void
|
|
e_system_inout_init(void)
|
|
{
|
|
_stdout_off();
|
|
_cmd_handlers = eina_hash_string_superfast_new(free);
|
|
_fdh_in = ecore_main_fd_handler_add(0, ECORE_FD_READ,
|
|
_cb_stdio_in_read, NULL,
|
|
NULL, NULL);
|
|
}
|
|
|
|
void
|
|
e_system_inout_shutdown(void)
|
|
{
|
|
ecore_main_fd_handler_del(_fdh_in);
|
|
_fdh_in = NULL;
|
|
eina_hash_free(_cmd_handlers);
|
|
_cmd_handlers = NULL;
|
|
_stdout_on();
|
|
}
|
|
|
|
void
|
|
e_system_inout_command_register(const char *cmd, void (*func) (void *data, const char *params), void *data)
|
|
{
|
|
Handler *h = malloc(sizeof(Handler));
|
|
size_t len = strlen(cmd);
|
|
if (!h)
|
|
{
|
|
ERR("Out of memory registering command handlers\n");
|
|
abort();
|
|
}
|
|
if (len > 23)
|
|
{
|
|
ERR("Trying to register command of length %i (max 23)\n", (int)len);
|
|
abort();
|
|
}
|
|
h->func = func;
|
|
h->data = data;
|
|
eina_hash_add(_cmd_handlers, cmd, h);
|
|
}
|
|
|
|
void EINA_PRINTF(2, 3)
|
|
e_system_inout_command_send(const char *cmd, const char *fmt, ...)
|
|
{
|
|
char *buf = NULL, stack_buf[4096];
|
|
Message_Head head;
|
|
size_t len = strlen(cmd);
|
|
int printed = 0;
|
|
ssize_t ret;
|
|
va_list ap;
|
|
|
|
if (len > 23)
|
|
{
|
|
ERR("Trying to send command of length %i (max 23)\n", (int)len);
|
|
abort();
|
|
}
|
|
if (fmt)
|
|
{
|
|
buf = stack_buf;
|
|
va_start(ap, fmt);
|
|
printed = vsnprintf(stack_buf, sizeof(stack_buf), fmt, ap);
|
|
va_end(ap);
|
|
if ((size_t)printed >= (sizeof(stack_buf) - 1))
|
|
{
|
|
buf = malloc(printed + 1);
|
|
if (!buf) goto end;
|
|
va_start(ap, fmt);
|
|
printed = vsnprintf(buf, printed + 1, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
|
|
memset(head.cmd, 0, sizeof(head.cmd));
|
|
memcpy(head.cmd, cmd, len);
|
|
if (printed > 0) head.size = printed + 1;
|
|
else head.size = 0;
|
|
ret = write(fd_supress, &head, sizeof(head));
|
|
if (ret != sizeof(head))
|
|
{
|
|
ERR("Write of command failed at %lli\n", (long long)ret);
|
|
abort();
|
|
}
|
|
if ((buf) && (head.size > 0))
|
|
{
|
|
ret = write(fd_supress, buf, head.size);
|
|
if (ret != (ssize_t)head.size)
|
|
{
|
|
ERR("Write of command buffer failed at %lli/%llu\n", (long long)ret, (unsigned long long)head.size);
|
|
abort();
|
|
}
|
|
}
|
|
end:
|
|
if (buf != stack_buf) free(buf);
|
|
}
|