Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ all: $(OUTPUT_DIR)/libs $(if $(ANDROID),,$(LUAJIT)) \
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO)),$(OUTPUT_DIR)/sftp-server,) \
$(if $(or $(DARWIN),$(WIN32)),,$(OUTPUT_DIR)/tar) \
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO),$(REMARKABLE)),$(OUTPUT_DIR)/fbink,) \
$(if $(KOBO),$(OUTPUT_DIR)/data/KoboUSBMS.tar.gz,) \
$(if $(REMARKABLE),$(OUTPUT_DIR)/button-listen,) \
$(SQLITE_LIB) \
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO),$(POCKETBOOK),$(REMARKABLE),$(SONY_PRSTUX)),$(CURL_LIB),) \
Expand Down
3 changes: 3 additions & 0 deletions Makefile.defs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,8 @@ OPENSSH_BUILD_DIR=$(THIRDPARTY_DIR)/openssh/build/$(MACHINE)
OPENSSH_DIR=$(CURDIR)/$(OPENSSH_BUILD_DIR)/openssh-prefix/src/openssh-build
FBINK_BUILD_DIR=$(THIRDPARTY_DIR)/fbink/build/$(MACHINE)
FBINK_DIR=$(CURDIR)/$(FBINK_BUILD_DIR)/fbink-prefix/src/fbink-build
KOBO_USBMS_BUILD_DIR=$(THIRDPARTY_DIR)/kobo-usbms/build/$(MACHINE)
KOBO_USBMS_DIR=$(CURDIR)/$(KOBO_USBMS_BUILD_DIR)/kobo-usbms-prefix/src/kobo-usbms-build

CURL_BUILD_DIR=$(THIRDPARTY_DIR)/curl/build/$(MACHINE)
CURL_DIR=$(CURDIR)/$(CURL_BUILD_DIR)/curl-prefix/src/curl-build
Expand Down Expand Up @@ -944,3 +946,4 @@ CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),tar,sdcv,libiconv,gettext,libj
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),openssl,dropbear,openssh
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),curl,zsync2
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),fbink
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),kobo-usbms
13 changes: 13 additions & 0 deletions Makefile.third
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,19 @@ ifdef REMARKABLE
cp $(FBINK_DIR)/fbdepth $(OUTPUT_DIR)/
endif

# ===========================================================================
# KoboUSBMS: Guess what?

$(OUTPUT_DIR)/data/KoboUSBMS.tar.gz: $(THIRDPARTY_DIR)/kobo-usbms/*.*
install -d $(KOBO_USBMS_BUILD_DIR)
cd $(KOBO_USBMS_BUILD_DIR) && \
$(CMAKE) $(CMAKE_FLAGS) \
-DCFLAGS="$(CFLAGS)" \
-DLDFLAGS="$(LDFLAGS)" \
$(CURDIR)/$(THIRDPARTY_DIR)/kobo-usbms && \
$(CMAKE_MAKE_PROGRAM) $(CMAKE_MAKE_PROGRAM_FLAGS)
cp $(KOBO_USBMS_DIR)/KoboUSBMS.tar.gz $(OUTPUT_DIR)/data/KoboUSBMS.tar.gz

# ===========================================================================
# common lua library for networking
$(LUASOCKET): $(THIRDPARTY_DIR)/luasocket/*.*
Expand Down
2 changes: 1 addition & 1 deletion ffi/framebuffer_linux.lua
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function framebuffer:init()
local finfo = ffi.new("struct fb_fix_screeninfo")
local vinfo = ffi.new("struct fb_var_screeninfo")

self.fd = C.open(self.device_node, C.O_RDWR)
self.fd = C.open(self.device_node, bit.bor(C.O_RDWR, C.O_CLOEXEC))
assert(self.fd ~= -1, "cannot open framebuffer")

-- Get fixed screen information
Expand Down
294 changes: 182 additions & 112 deletions input/libue.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,144 +22,214 @@
SOFTWARE.
*/

#ifndef _LIBUE_H
#define _LIBUE_H
#ifndef __LIBUE_H
#define __LIBUE_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>

#include <linux/netlink.h>
#include <stdio.h>

#define LIBUE_VERSION_MAJOR "0"
#define LIBUE_VERSION_MINOR "1.0"
#define LIBUE_VERSION LIBUE_VERSION_MAJOR "." LIBUE_VERSION_MINOR
#define LIBUE_VERSION_MAJOR "0"
#define LIBUE_VERSION_MINOR "3.0"
#define LIBUE_VERSION LIBUE_VERSION_MAJOR "." LIBUE_VERSION_MINOR
#define LIBUE_VERSION_NUMBER 10000
#ifndef DEBUG
#define DEBUG 0

// Enable debug logging in Debug builds
#ifdef DEBUG
# define UE_DEBUG 1
#else
# define UE_DEBUG 0
#endif
#define UE_DEBUG(...) \
do { if (DEBUG) fprintf(stderr, __VA_ARGS__); } while(0)

struct uevent_listener {
struct pollfd pfd;
struct sockaddr_nl nls;
// We don't log to syslog
#define UE_SYSLOG 0

// Logging helpers
#define UE_LOG(prio, fmt, ...) \
({ \
if (UE_SYSLOG) { \
syslog(prio, fmt, ##__VA_ARGS__); \
} else { \
fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
} \
})

// Same, but with __PRETTY_FUNCTION__:__LINE__ right before fmt
#define UE_PFLOG(prio, fmt, ...) \
({ \
if ((prio != LOG_DEBUG) || (prio == LOG_DEBUG && UE_DEBUG)) { \
UE_LOG(prio, "[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); \
} \
})

struct uevent_listener
{
struct pollfd pfd;
struct sockaddr_nl nls;
};

#define ERR_LISTENER_NOT_ROOT -1
#define ERR_LISTENER_BIND -2
#define ERR_LISTENER_POLL -3
#define ERR_LISTENER_RECV -4
#define ERR_PARSE_UDEV -1
#define ERR_PARSE_INVALID_HDR -2
#define UE_STR_EQ(str, const_str) (strncmp((str), (const_str), sizeof(const_str)-1) == 0)

enum uevent_action {
UEVENT_ACTION_INVALID = 0,
UEVENT_ACTION_ADD,
UEVENT_ACTION_REMOVE,
UEVENT_ACTION_CHANGE,
UEVENT_ACTION_MOVE,
UEVENT_ACTION_ONLINE,
UEVENT_ACTION_OFFLINE,
#define ERR_LISTENER_NOT_ROOT -1
#define ERR_LISTENER_BIND -2
#define ERR_LISTENER_POLL -3
#define ERR_LISTENER_RECV -4
#define ERR_PARSE_UDEV -1
#define ERR_PARSE_INVALID_HDR -2
#define UE_STR_EQ(str, const_str) (strncmp((str), (const_str), sizeof(const_str) - 1U) == 0)

enum uevent_action
{
UEVENT_ACTION_INVALID = 0,
UEVENT_ACTION_ADD,
UEVENT_ACTION_REMOVE,
UEVENT_ACTION_CHANGE,
UEVENT_ACTION_MOVE,
UEVENT_ACTION_ONLINE,
UEVENT_ACTION_OFFLINE,
};

struct uevent {
enum uevent_action action;
char *devpath;
char buf[4096];
size_t buflen;
};
static const char* uev_action_str[] = { "invalid", "add", "remove", "change", "move", "online", "offline" };

const char* uev_action_str[] = { "invalid", "add", "remove", "change", "move", "online", "offline" };
struct uevent
{
enum uevent_action action;
char* devpath;
char buf[PIPE_BUF];
size_t buflen;
};

/*
* Reference for uevent format:
* https://www.kernel.org/doc/pending/hotplug.txt
* https://stackoverflow.com/a/22813783
*/
int ue_parse_event_msg(struct uevent *uevp, size_t buflen) {
/* skip udev events */
if (memcmp(uevp->buf, "libudev", 8) == 0) return ERR_PARSE_UDEV;

/* validate message header */
int body_start = strlen(uevp->buf) + 1;
if ((size_t)body_start < sizeof("a@/d")
|| body_start >= buflen
|| (strstr(uevp->buf, "@/") == NULL)) {
return ERR_PARSE_INVALID_HDR;
}

int i = body_start;
char *cur_line;
uevp->buflen = buflen;

while (i < buflen) {
cur_line = uevp->buf + i;
UE_DEBUG("line: '%s'\n", cur_line);
if (UE_STR_EQ(cur_line, "ACTION")) {
cur_line += sizeof("ACTION");
if (UE_STR_EQ(cur_line, "add")) {
uevp->action = UEVENT_ACTION_ADD;
} else if (UE_STR_EQ(cur_line, "change")) {
uevp->action = UEVENT_ACTION_CHANGE;
} else if (UE_STR_EQ(cur_line, "remove")) {
uevp->action = UEVENT_ACTION_REMOVE;
} else if (UE_STR_EQ(cur_line, "move")) {
uevp->action = UEVENT_ACTION_MOVE;
} else if (UE_STR_EQ(cur_line, "online")) {
uevp->action = UEVENT_ACTION_ONLINE;
} else if (UE_STR_EQ(cur_line, "offline")) {
uevp->action = UEVENT_ACTION_OFFLINE;
}
} else if (UE_STR_EQ(cur_line, "DEVPATH")) {
uevp->devpath = cur_line + sizeof("DEVPATH");
}
/* proceed to next line */
i += strlen(cur_line) + 1;
}
return 0;
static int
ue_parse_event_msg(struct uevent* uevp, size_t buflen)
{
/* skip udev events */
if (memcmp(uevp->buf, "libudev", 7) == 0 || memcmp(uevp->buf, "udev", 4) == 0) {
return ERR_PARSE_UDEV;
}

/* validate message header */
size_t body_start = strlen(uevp->buf) + 1U;
if (body_start < sizeof("a@/d") || body_start >= buflen || (strstr(uevp->buf, "@/") == NULL)) {
return ERR_PARSE_INVALID_HDR;
}

size_t i = body_start;
char* cur_line;
uevp->buflen = buflen;

while (i < buflen) {
cur_line = uevp->buf + i;
UE_PFLOG(LOG_DEBUG, "line: `%s`", cur_line);
char* p = cur_line;
if (UE_STR_EQ(p, "ACTION")) {
p += sizeof("ACTION");
if (UE_STR_EQ(p, "add")) {
uevp->action = UEVENT_ACTION_ADD;
} else if (UE_STR_EQ(p, "change")) {
uevp->action = UEVENT_ACTION_CHANGE;
} else if (UE_STR_EQ(p, "remove")) {
uevp->action = UEVENT_ACTION_REMOVE;
} else if (UE_STR_EQ(p, "move")) {
uevp->action = UEVENT_ACTION_MOVE;
} else if (UE_STR_EQ(p, "online")) {
uevp->action = UEVENT_ACTION_ONLINE;
} else if (UE_STR_EQ(p, "offline")) {
uevp->action = UEVENT_ACTION_OFFLINE;
}
} else if (UE_STR_EQ(p, "DEVPATH")) {
uevp->devpath = p + sizeof("DEVPATH");
}
/* proceed to next line */
i += strlen(cur_line) + 1U;
}
return EXIT_SUCCESS;
}

inline void ue_dump_event(struct uevent *uevp) {
printf("%s %s\n", uev_action_str[uevp->action], uevp->devpath);
static inline void
ue_dump_event(struct uevent* uevp)
{
printf("%s %s\n", uev_action_str[uevp->action], uevp->devpath);
}

inline void ue_reset_event(struct uevent *uevp) {
uevp->action = UEVENT_ACTION_INVALID;
uevp->buflen = 0;
uevp->devpath = NULL;
static inline void
ue_reset_event(struct uevent* uevp)
{
uevp->action = UEVENT_ACTION_INVALID;
uevp->devpath = NULL;
uevp->buflen = 0U;
}

int ue_init_listener(struct uevent_listener *l) {
memset(&l->nls, 0, sizeof(struct sockaddr_nl));
l->nls.nl_family = AF_NETLINK;
l->nls.nl_pid = getpid();
l->nls.nl_groups = -1;

l->pfd.events = POLLIN;
l->pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (l->pfd.fd == -1) return ERR_LISTENER_NOT_ROOT;

if (bind(l->pfd.fd, (void *)&(l->nls), sizeof(struct sockaddr_nl))) {
return ERR_LISTENER_BIND;
}
static int
ue_init_listener(struct uevent_listener* l)
{
memset(&l->nls, 0, sizeof(struct sockaddr_nl));
l->nls.nl_family = AF_NETLINK;
// NOTE: It's actually a pid_t in non-braindead kernels...
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
l->nls.nl_pid = getpid();
#pragma GCC diagnostic pop
l->nls.nl_groups = -1U;

l->pfd.events = POLLIN;
l->pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (l->pfd.fd == -1) {
UE_PFLOG(LOG_CRIT, "socket: %m");
return ERR_LISTENER_NOT_ROOT;
}

if (bind(l->pfd.fd, (struct sockaddr*) &(l->nls), sizeof(struct sockaddr_nl))) {
UE_PFLOG(LOG_CRIT, "bind: %m");
return ERR_LISTENER_BIND;
}

return EXIT_SUCCESS;
}

return 0;
static int
ue_wait_for_event(struct uevent_listener* l, struct uevent* uevp)
{
while (poll(&(l->pfd), 1, -1) != -1) {
ue_reset_event(uevp);
ssize_t len = recv(l->pfd.fd, uevp->buf, sizeof(uevp->buf), MSG_DONTWAIT);
if (len == -1) {
UE_PFLOG(LOG_CRIT, "recv: %m");
return ERR_LISTENER_RECV;
}
int rc = ue_parse_event_msg(uevp, (size_t) len);
if (rc == EXIT_SUCCESS) {
UE_PFLOG(LOG_DEBUG, "uevent successfully parsed");
return EXIT_SUCCESS;
} else if (rc == ERR_PARSE_UDEV) {
UE_PFLOG(LOG_DEBUG, "skipped udev uevent: `%s`", uevp->buf);
} else if (rc == ERR_PARSE_INVALID_HDR) {
UE_PFLOG(LOG_DEBUG, "skipped malformed uevent: `%s`", uevp->buf);
} else {
UE_PFLOG(LOG_DEBUG, "skipped unsupported uevent: `%s`", uevp->buf);
}
}
UE_PFLOG(LOG_CRIT, "poll: %m");
return ERR_LISTENER_POLL;
}

int ue_wait_for_event(struct uevent_listener *l, struct uevent *uevp) {
ue_reset_event(uevp);
while (poll(&(l->pfd), 1, -1) != -1) {
int i, len = recv(l->pfd.fd, uevp->buf, sizeof(uevp->buf), MSG_DONTWAIT);
if (len == -1) return ERR_LISTENER_RECV;
if (ue_parse_event_msg(uevp, len) == 0) {
UE_DEBUG("uevent successfully parsed\n");
return 0;
} else {
UE_DEBUG("skipped unsupported uevent:\n%s\n", uevp->buf);
}
}
return ERR_LISTENER_POLL;
static int
ue_destroy_listener(struct uevent_listener* l)
{
if (l->pfd.fd != -1) {
return close(l->pfd.fd);
} else {
return EXIT_SUCCESS;
}
}

#endif
#endif // __LIBUE_H
Loading