Skip to content

Commit f13c503

Browse files
authored
Build KoboUSBMS on Kobo (koreader#1165)
* Build KoboUSBMS on Kobo for... USBMS. * And sprinkle a bit of CLOEXEC magic in framebuffer_linux while we're at it.
1 parent 1cc6b95 commit f13c503

File tree

6 files changed

+244
-113
lines changed

6 files changed

+244
-113
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ all: $(OUTPUT_DIR)/libs $(if $(ANDROID),,$(LUAJIT)) \
3636
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO)),$(OUTPUT_DIR)/sftp-server,) \
3737
$(if $(or $(DARWIN),$(WIN32)),,$(OUTPUT_DIR)/tar) \
3838
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO),$(REMARKABLE)),$(OUTPUT_DIR)/fbink,) \
39+
$(if $(KOBO),$(OUTPUT_DIR)/data/KoboUSBMS.tar.gz,) \
3940
$(if $(REMARKABLE),$(OUTPUT_DIR)/button-listen,) \
4041
$(SQLITE_LIB) \
4142
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO),$(POCKETBOOK),$(REMARKABLE),$(SONY_PRSTUX)),$(CURL_LIB),) \

Makefile.defs

+3
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,8 @@ OPENSSH_BUILD_DIR=$(THIRDPARTY_DIR)/openssh/build/$(MACHINE)
836836
OPENSSH_DIR=$(CURDIR)/$(OPENSSH_BUILD_DIR)/openssh-prefix/src/openssh-build
837837
FBINK_BUILD_DIR=$(THIRDPARTY_DIR)/fbink/build/$(MACHINE)
838838
FBINK_DIR=$(CURDIR)/$(FBINK_BUILD_DIR)/fbink-prefix/src/fbink-build
839+
KOBO_USBMS_BUILD_DIR=$(THIRDPARTY_DIR)/kobo-usbms/build/$(MACHINE)
840+
KOBO_USBMS_DIR=$(CURDIR)/$(KOBO_USBMS_BUILD_DIR)/kobo-usbms-prefix/src/kobo-usbms-build
839841

840842
CURL_BUILD_DIR=$(THIRDPARTY_DIR)/curl/build/$(MACHINE)
841843
CURL_DIR=$(CURDIR)/$(CURL_BUILD_DIR)/curl-prefix/src/curl-build
@@ -944,3 +946,4 @@ CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),tar,sdcv,libiconv,gettext,libj
944946
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),openssl,dropbear,openssh
945947
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),curl,zsync2
946948
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),fbink
949+
CMAKE_THIRDPARTY_LIBS := $(CMAKE_THIRDPARTY_LIBS),kobo-usbms

Makefile.third

+13
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,19 @@ ifdef REMARKABLE
504504
cp $(FBINK_DIR)/fbdepth $(OUTPUT_DIR)/
505505
endif
506506

507+
# ===========================================================================
508+
# KoboUSBMS: Guess what?
509+
510+
$(OUTPUT_DIR)/data/KoboUSBMS.tar.gz: $(THIRDPARTY_DIR)/kobo-usbms/*.*
511+
install -d $(KOBO_USBMS_BUILD_DIR)
512+
cd $(KOBO_USBMS_BUILD_DIR) && \
513+
$(CMAKE) $(CMAKE_FLAGS) \
514+
-DCFLAGS="$(CFLAGS)" \
515+
-DLDFLAGS="$(LDFLAGS)" \
516+
$(CURDIR)/$(THIRDPARTY_DIR)/kobo-usbms && \
517+
$(CMAKE_MAKE_PROGRAM) $(CMAKE_MAKE_PROGRAM_FLAGS)
518+
cp $(KOBO_USBMS_DIR)/KoboUSBMS.tar.gz $(OUTPUT_DIR)/data/KoboUSBMS.tar.gz
519+
507520
# ===========================================================================
508521
# common lua library for networking
509522
$(LUASOCKET): $(THIRDPARTY_DIR)/luasocket/*.*

ffi/framebuffer_linux.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function framebuffer:init()
9494
local finfo = ffi.new("struct fb_fix_screeninfo")
9595
local vinfo = ffi.new("struct fb_var_screeninfo")
9696

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

100100
-- Get fixed screen information

input/libue.h

+182-112
Original file line numberDiff line numberDiff line change
@@ -22,144 +22,214 @@
2222
SOFTWARE.
2323
*/
2424

25-
#ifndef _LIBUE_H
26-
#define _LIBUE_H
25+
#ifndef __LIBUE_H
26+
#define __LIBUE_H
2727

28+
#include <stdio.h>
29+
#include <stdlib.h>
30+
#include <string.h>
2831
#include <sys/poll.h>
2932
#include <sys/socket.h>
30-
#include <string.h>
33+
#include <sys/types.h>
34+
#include <syslog.h>
35+
#include <unistd.h>
36+
3137
#include <linux/netlink.h>
32-
#include <stdio.h>
3338

34-
#define LIBUE_VERSION_MAJOR "0"
35-
#define LIBUE_VERSION_MINOR "1.0"
36-
#define LIBUE_VERSION LIBUE_VERSION_MAJOR "." LIBUE_VERSION_MINOR
39+
#define LIBUE_VERSION_MAJOR "0"
40+
#define LIBUE_VERSION_MINOR "3.0"
41+
#define LIBUE_VERSION LIBUE_VERSION_MAJOR "." LIBUE_VERSION_MINOR
3742
#define LIBUE_VERSION_NUMBER 10000
38-
#ifndef DEBUG
39-
#define DEBUG 0
43+
44+
// Enable debug logging in Debug builds
45+
#ifdef DEBUG
46+
# define UE_DEBUG 1
47+
#else
48+
# define UE_DEBUG 0
4049
#endif
41-
#define UE_DEBUG(...) \
42-
do { if (DEBUG) fprintf(stderr, __VA_ARGS__); } while(0)
4350

44-
struct uevent_listener {
45-
struct pollfd pfd;
46-
struct sockaddr_nl nls;
51+
// We don't log to syslog
52+
#define UE_SYSLOG 0
53+
54+
// Logging helpers
55+
#define UE_LOG(prio, fmt, ...) \
56+
({ \
57+
if (UE_SYSLOG) { \
58+
syslog(prio, fmt, ##__VA_ARGS__); \
59+
} else { \
60+
fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
61+
} \
62+
})
63+
64+
// Same, but with __PRETTY_FUNCTION__:__LINE__ right before fmt
65+
#define UE_PFLOG(prio, fmt, ...) \
66+
({ \
67+
if ((prio != LOG_DEBUG) || (prio == LOG_DEBUG && UE_DEBUG)) { \
68+
UE_LOG(prio, "[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); \
69+
} \
70+
})
71+
72+
struct uevent_listener
73+
{
74+
struct pollfd pfd;
75+
struct sockaddr_nl nls;
4776
};
4877

49-
#define ERR_LISTENER_NOT_ROOT -1
50-
#define ERR_LISTENER_BIND -2
51-
#define ERR_LISTENER_POLL -3
52-
#define ERR_LISTENER_RECV -4
53-
#define ERR_PARSE_UDEV -1
54-
#define ERR_PARSE_INVALID_HDR -2
55-
#define UE_STR_EQ(str, const_str) (strncmp((str), (const_str), sizeof(const_str)-1) == 0)
56-
57-
enum uevent_action {
58-
UEVENT_ACTION_INVALID = 0,
59-
UEVENT_ACTION_ADD,
60-
UEVENT_ACTION_REMOVE,
61-
UEVENT_ACTION_CHANGE,
62-
UEVENT_ACTION_MOVE,
63-
UEVENT_ACTION_ONLINE,
64-
UEVENT_ACTION_OFFLINE,
78+
#define ERR_LISTENER_NOT_ROOT -1
79+
#define ERR_LISTENER_BIND -2
80+
#define ERR_LISTENER_POLL -3
81+
#define ERR_LISTENER_RECV -4
82+
#define ERR_PARSE_UDEV -1
83+
#define ERR_PARSE_INVALID_HDR -2
84+
#define UE_STR_EQ(str, const_str) (strncmp((str), (const_str), sizeof(const_str) - 1U) == 0)
85+
86+
enum uevent_action
87+
{
88+
UEVENT_ACTION_INVALID = 0,
89+
UEVENT_ACTION_ADD,
90+
UEVENT_ACTION_REMOVE,
91+
UEVENT_ACTION_CHANGE,
92+
UEVENT_ACTION_MOVE,
93+
UEVENT_ACTION_ONLINE,
94+
UEVENT_ACTION_OFFLINE,
6595
};
6696

67-
struct uevent {
68-
enum uevent_action action;
69-
char *devpath;
70-
char buf[4096];
71-
size_t buflen;
72-
};
97+
static const char* uev_action_str[] = { "invalid", "add", "remove", "change", "move", "online", "offline" };
7398

74-
const char* uev_action_str[] = { "invalid", "add", "remove", "change", "move", "online", "offline" };
99+
struct uevent
100+
{
101+
enum uevent_action action;
102+
char* devpath;
103+
char buf[PIPE_BUF];
104+
size_t buflen;
105+
};
75106

76107
/*
77108
* Reference for uevent format:
78109
* https://www.kernel.org/doc/pending/hotplug.txt
110+
* https://stackoverflow.com/a/22813783
79111
*/
80-
int ue_parse_event_msg(struct uevent *uevp, size_t buflen) {
81-
/* skip udev events */
82-
if (memcmp(uevp->buf, "libudev", 8) == 0) return ERR_PARSE_UDEV;
83-
84-
/* validate message header */
85-
int body_start = strlen(uevp->buf) + 1;
86-
if ((size_t)body_start < sizeof("a@/d")
87-
|| body_start >= buflen
88-
|| (strstr(uevp->buf, "@/") == NULL)) {
89-
return ERR_PARSE_INVALID_HDR;
90-
}
91-
92-
int i = body_start;
93-
char *cur_line;
94-
uevp->buflen = buflen;
95-
96-
while (i < buflen) {
97-
cur_line = uevp->buf + i;
98-
UE_DEBUG("line: '%s'\n", cur_line);
99-
if (UE_STR_EQ(cur_line, "ACTION")) {
100-
cur_line += sizeof("ACTION");
101-
if (UE_STR_EQ(cur_line, "add")) {
102-
uevp->action = UEVENT_ACTION_ADD;
103-
} else if (UE_STR_EQ(cur_line, "change")) {
104-
uevp->action = UEVENT_ACTION_CHANGE;
105-
} else if (UE_STR_EQ(cur_line, "remove")) {
106-
uevp->action = UEVENT_ACTION_REMOVE;
107-
} else if (UE_STR_EQ(cur_line, "move")) {
108-
uevp->action = UEVENT_ACTION_MOVE;
109-
} else if (UE_STR_EQ(cur_line, "online")) {
110-
uevp->action = UEVENT_ACTION_ONLINE;
111-
} else if (UE_STR_EQ(cur_line, "offline")) {
112-
uevp->action = UEVENT_ACTION_OFFLINE;
113-
}
114-
} else if (UE_STR_EQ(cur_line, "DEVPATH")) {
115-
uevp->devpath = cur_line + sizeof("DEVPATH");
116-
}
117-
/* proceed to next line */
118-
i += strlen(cur_line) + 1;
119-
}
120-
return 0;
112+
static int
113+
ue_parse_event_msg(struct uevent* uevp, size_t buflen)
114+
{
115+
/* skip udev events */
116+
if (memcmp(uevp->buf, "libudev", 7) == 0 || memcmp(uevp->buf, "udev", 4) == 0) {
117+
return ERR_PARSE_UDEV;
118+
}
119+
120+
/* validate message header */
121+
size_t body_start = strlen(uevp->buf) + 1U;
122+
if (body_start < sizeof("a@/d") || body_start >= buflen || (strstr(uevp->buf, "@/") == NULL)) {
123+
return ERR_PARSE_INVALID_HDR;
124+
}
125+
126+
size_t i = body_start;
127+
char* cur_line;
128+
uevp->buflen = buflen;
129+
130+
while (i < buflen) {
131+
cur_line = uevp->buf + i;
132+
UE_PFLOG(LOG_DEBUG, "line: `%s`", cur_line);
133+
char* p = cur_line;
134+
if (UE_STR_EQ(p, "ACTION")) {
135+
p += sizeof("ACTION");
136+
if (UE_STR_EQ(p, "add")) {
137+
uevp->action = UEVENT_ACTION_ADD;
138+
} else if (UE_STR_EQ(p, "change")) {
139+
uevp->action = UEVENT_ACTION_CHANGE;
140+
} else if (UE_STR_EQ(p, "remove")) {
141+
uevp->action = UEVENT_ACTION_REMOVE;
142+
} else if (UE_STR_EQ(p, "move")) {
143+
uevp->action = UEVENT_ACTION_MOVE;
144+
} else if (UE_STR_EQ(p, "online")) {
145+
uevp->action = UEVENT_ACTION_ONLINE;
146+
} else if (UE_STR_EQ(p, "offline")) {
147+
uevp->action = UEVENT_ACTION_OFFLINE;
148+
}
149+
} else if (UE_STR_EQ(p, "DEVPATH")) {
150+
uevp->devpath = p + sizeof("DEVPATH");
151+
}
152+
/* proceed to next line */
153+
i += strlen(cur_line) + 1U;
154+
}
155+
return EXIT_SUCCESS;
121156
}
122157

123-
inline void ue_dump_event(struct uevent *uevp) {
124-
printf("%s %s\n", uev_action_str[uevp->action], uevp->devpath);
158+
static inline void
159+
ue_dump_event(struct uevent* uevp)
160+
{
161+
printf("%s %s\n", uev_action_str[uevp->action], uevp->devpath);
125162
}
126163

127-
inline void ue_reset_event(struct uevent *uevp) {
128-
uevp->action = UEVENT_ACTION_INVALID;
129-
uevp->buflen = 0;
130-
uevp->devpath = NULL;
164+
static inline void
165+
ue_reset_event(struct uevent* uevp)
166+
{
167+
uevp->action = UEVENT_ACTION_INVALID;
168+
uevp->devpath = NULL;
169+
uevp->buflen = 0U;
131170
}
132171

133-
int ue_init_listener(struct uevent_listener *l) {
134-
memset(&l->nls, 0, sizeof(struct sockaddr_nl));
135-
l->nls.nl_family = AF_NETLINK;
136-
l->nls.nl_pid = getpid();
137-
l->nls.nl_groups = -1;
138-
139-
l->pfd.events = POLLIN;
140-
l->pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
141-
if (l->pfd.fd == -1) return ERR_LISTENER_NOT_ROOT;
142-
143-
if (bind(l->pfd.fd, (void *)&(l->nls), sizeof(struct sockaddr_nl))) {
144-
return ERR_LISTENER_BIND;
145-
}
172+
static int
173+
ue_init_listener(struct uevent_listener* l)
174+
{
175+
memset(&l->nls, 0, sizeof(struct sockaddr_nl));
176+
l->nls.nl_family = AF_NETLINK;
177+
// NOTE: It's actually a pid_t in non-braindead kernels...
178+
#pragma GCC diagnostic push
179+
#pragma GCC diagnostic ignored "-Wsign-conversion"
180+
l->nls.nl_pid = getpid();
181+
#pragma GCC diagnostic pop
182+
l->nls.nl_groups = -1U;
183+
184+
l->pfd.events = POLLIN;
185+
l->pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
186+
if (l->pfd.fd == -1) {
187+
UE_PFLOG(LOG_CRIT, "socket: %m");
188+
return ERR_LISTENER_NOT_ROOT;
189+
}
190+
191+
if (bind(l->pfd.fd, (struct sockaddr*) &(l->nls), sizeof(struct sockaddr_nl))) {
192+
UE_PFLOG(LOG_CRIT, "bind: %m");
193+
return ERR_LISTENER_BIND;
194+
}
195+
196+
return EXIT_SUCCESS;
197+
}
146198

147-
return 0;
199+
static int
200+
ue_wait_for_event(struct uevent_listener* l, struct uevent* uevp)
201+
{
202+
while (poll(&(l->pfd), 1, -1) != -1) {
203+
ue_reset_event(uevp);
204+
ssize_t len = recv(l->pfd.fd, uevp->buf, sizeof(uevp->buf), MSG_DONTWAIT);
205+
if (len == -1) {
206+
UE_PFLOG(LOG_CRIT, "recv: %m");
207+
return ERR_LISTENER_RECV;
208+
}
209+
int rc = ue_parse_event_msg(uevp, (size_t) len);
210+
if (rc == EXIT_SUCCESS) {
211+
UE_PFLOG(LOG_DEBUG, "uevent successfully parsed");
212+
return EXIT_SUCCESS;
213+
} else if (rc == ERR_PARSE_UDEV) {
214+
UE_PFLOG(LOG_DEBUG, "skipped udev uevent: `%s`", uevp->buf);
215+
} else if (rc == ERR_PARSE_INVALID_HDR) {
216+
UE_PFLOG(LOG_DEBUG, "skipped malformed uevent: `%s`", uevp->buf);
217+
} else {
218+
UE_PFLOG(LOG_DEBUG, "skipped unsupported uevent: `%s`", uevp->buf);
219+
}
220+
}
221+
UE_PFLOG(LOG_CRIT, "poll: %m");
222+
return ERR_LISTENER_POLL;
148223
}
149224

150-
int ue_wait_for_event(struct uevent_listener *l, struct uevent *uevp) {
151-
ue_reset_event(uevp);
152-
while (poll(&(l->pfd), 1, -1) != -1) {
153-
int i, len = recv(l->pfd.fd, uevp->buf, sizeof(uevp->buf), MSG_DONTWAIT);
154-
if (len == -1) return ERR_LISTENER_RECV;
155-
if (ue_parse_event_msg(uevp, len) == 0) {
156-
UE_DEBUG("uevent successfully parsed\n");
157-
return 0;
158-
} else {
159-
UE_DEBUG("skipped unsupported uevent:\n%s\n", uevp->buf);
160-
}
161-
}
162-
return ERR_LISTENER_POLL;
225+
static int
226+
ue_destroy_listener(struct uevent_listener* l)
227+
{
228+
if (l->pfd.fd != -1) {
229+
return close(l->pfd.fd);
230+
} else {
231+
return EXIT_SUCCESS;
232+
}
163233
}
164234

165-
#endif
235+
#endif // __LIBUE_H

0 commit comments

Comments
 (0)