enlightenment/src/bin/system/e_system_inout.c

172 lines
4.2 KiB
C
Raw Normal View History

#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 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();
}
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)
{
_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;
}
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(1, &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(1, 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);
}