From 1a746d6e8ffd9bccad8682704d03f60f1cde129e Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 02:09:43 +0200 Subject: [PATCH 01/19] Makefile tweaks for my TC --- Makefile | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 7f4f9258b..37c2aec2a 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ TTF_FONTS_DIR=$(MUPDFDIR)/fonts # set this to your ARM cross compiler: -HOST:=arm-none-linux-gnueabi +HOST:=arm-kindle-linux-gnueabi CC:=$(HOST)-gcc CXX:=$(HOST)-g++ STRIP:=$(HOST)-strip @@ -27,10 +27,14 @@ endif HOSTCC:=gcc HOSTCXX:=g++ -CFLAGS:=-O3 $(SYSROOT) -CXXFLAGS:=-O3 $(SYSROOT) +# Base CFLAGS, without arch. Will use it as-is for luajit, because its buildsystem picks up the wrong flags, possibly from my env... +BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer -fno-stack-protector -U_FORTIFY_SOURCE + +CFLAGS:=$(BASE_CFLAGS) +CXXFLAGS:=$(BASE_CFLAGS) -fno-use-cxa-atexit LDFLAGS:=-Wl,-O1 -Wl,--as-needed ARM_CFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp +HOSTCFLAGS:=-O2 -march=native -ffast-math -pipe -fomit-frame-pointer # use this for debugging: #CFLAGS:=-O0 -g @@ -92,6 +96,7 @@ all:kpdfview kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) $(CC) \ + $(CFLAGS) \ kpdfview.o \ einkfb.o \ pdf.o \ @@ -110,6 +115,7 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft cre.o \ $(CRENGINELIBS) \ $(STATICLIBSTDCPP) \ + $(LDFLAGS) \ -o kpdfview -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP) slider_watcher: slider_watcher.c @@ -158,7 +164,7 @@ clean: -rm -f *.o kpdfview slider_watcher cleanthirdparty: - -make -C $(LUADIR) clean + -make -C $(LUADIR) clean CFLAGS="" -make -C $(MUPDFDIR) build="release" clean -make -C $(CRENGINEDIR)/thirdparty/antiword clean test -d $(CRENGINEDIR)/thirdparty/chmlib && make -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found @@ -170,12 +176,12 @@ cleanthirdparty: -rm -f $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.host: - make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump + make -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/fontdump cp -a $(MUPDFLIBDIR)/fontdump $(MUPDFDIR)/fontdump.host make -C mupdf clean $(MUPDFDIR)/cmapdump.host: - make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump + make -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/cmapdump cp -a $(MUPDFLIBDIR)/cmapdump $(MUPDFDIR)/cmapdump.host make -C mupdf clean @@ -201,7 +207,7 @@ $(LUALIB): ifdef EMULATE_READER make -C $(LUADIR) else - make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(HOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" + make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(BASE_CFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(HOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" V=1 endif thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) From d27f20d6968912b2c3b0aa3cffb94f35455ede93 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 02:16:22 +0200 Subject: [PATCH 02/19] Fix input device closing, and fix lipc-wait-event handling (using popen-noshell from http://code.google.com/p/popen-noshell/) --- Makefile | 8 +- input.c | 100 +++++-- kpdfview.c | 17 +- launchpad/kpdf.sh | 4 - popen-noshell/README | 21 ++ popen-noshell/popen_noshell.c | 550 ++++++++++++++++++++++++++++++++++ popen-noshell/popen_noshell.h | 69 +++++ 7 files changed, 740 insertions(+), 29 deletions(-) create mode 100644 popen-noshell/README create mode 100644 popen-noshell/popen_noshell.c create mode 100644 popen-noshell/popen_noshell.h diff --git a/Makefile b/Makefile index 37c2aec2a..551feef2b 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,8 @@ CRENGINEDIR=$(KPVCRLIBDIR)/crengine FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype-2.4.10 LFSDIR=luafilesystem +POPENNSDIR=popen-noshell + # must point to directory with *.ttf fonts for crengine TTF_FONTS_DIR=$(MUPDFDIR)/fonts @@ -94,7 +96,7 @@ LUALIB := $(LUADIR)/src/libluajit.a all:kpdfview -kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) +kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o popen_noshell.o input.o util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) $(CC) \ $(CFLAGS) \ kpdfview.o \ @@ -102,6 +104,7 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o util.o ft pdf.o \ blitbuffer.o \ drawcontext.o \ + popen_noshell.o \ input.o \ util.o \ ft.o \ @@ -136,6 +139,9 @@ cre.o: %.o: %.cpp lfs.o: $(LFSDIR)/src/lfs.c $(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@ +popen_noshell.o: $(POPENNSDIR)/popen_noshell.c + $(CC) -c $(CFLAGS) -I$(POPENNSDIR) $(POPENNSDIR)/popen_noshell.c -o $@ + fetchthirdparty: -rm -Rf mupdf/thirdparty test -d mupdf && (cd mupdf; git checkout .) || echo warn: mupdf folder not found diff --git a/input.c b/input.c index fffc35d61..9176659f3 100644 --- a/input.c +++ b/input.c @@ -15,7 +15,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + +#include "popen-noshell/popen_noshell.h" +#include #include +#include #include #include #include @@ -31,7 +35,6 @@ #include #include -#define OUTPUT_SIZE 21 #define CODE_IN_SAVER 10000 #define CODE_OUT_SAVER 10001 #define CODE_USB_PLUG_IN 10010 @@ -41,7 +44,18 @@ #define NUM_FDS 4 int inputfds[4] = { -1, -1, -1, -1 }; -int slider_pid = -1; +pid_t slider_pid = -1; +struct popen_noshell_pass_to_pclose pclose_arg; + +void slider_handler(int sig) +{ + int status; + /* Kill lipc-wait-event properly on exit */ + if(pclose_arg.pid != 0) { + status = kill(pclose_arg.pid, SIGTERM); + printf("[SIGTERM] kill returned %d\n", status); + } +} int findFreeFdSlot() { int i; @@ -63,6 +77,8 @@ static int openInputDevice(lua_State *L) { return luaL_error(L, "no free slot for new input device <%s>", inputdevice); } + printf("Opening input device <%s> in slot %d.\n", inputdevice, fd); + if(!strcmp("slider",inputdevice)) { /* special case: the power slider */ int pipefd[2]; @@ -73,10 +89,13 @@ static int openInputDevice(lua_State *L) { return luaL_error(L, "cannot fork() slider event listener"); } if(childpid == 0) { + // Setup signal handler, to cleanup on exit + signal(SIGTERM, slider_handler); + FILE *fp; - char std_out[OUTPUT_SIZE] = ""; + char std_out[256]; + int status; struct input_event ev; - int ret; __u16 key_code = 10000; close(pipefd[0]); @@ -86,16 +105,27 @@ static int openInputDevice(lua_State *L) { ev.value = 1; /* listen power slider events */ - while(1) { - fp = popen("exec lipc-wait-event com.lab126.powerd goingToScreenSaver,outOfScreenSaver,charging,notCharging", "r"); - /* @TODO 07.06 2012 (houqp) - * plugin and out event can only be watched by: - lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn - */ - if(fgets(std_out, OUTPUT_SIZE, fp) == NULL) { - break; - } - pclose(fp); + char *exec_file = "lipc-wait-event"; + char *arg1 = "-m"; // Hang for ever, don't exit on the first one, we're in a dedicated child, and we'll be closed on exit, so we don't care + char *arg2 = "-s"; + char *arg3 = "0"; + char *arg4 = "com.lab126.powerd"; + char *arg5 = "goingToScreenSaver,outOfScreenSaver,charging,notCharging"; + char *arg6 = (char *) NULL; + char *argv[] = {exec_file, arg1, arg2, arg3, arg4, arg5, arg6}; + /* @TODO 07.06 2012 (houqp) + * plugin and out event can only be watched by: + lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn + */ + + fp = popen_noshell(exec_file, (const char * const *)argv, "r", &pclose_arg, 0); + if (!fp) { + err(EXIT_FAILURE, "popen_noshell()"); + } + + printf("PID of our child is: %d (ours: %d)\n", (int)pclose_arg.pid, (int)getpid()); + + while(fgets(std_out, sizeof(std_out)-1, fp)) { if(std_out[0] == 'g') { ev.code = CODE_IN_SAVER; } else if(std_out[0] == 'o') { @@ -116,14 +146,32 @@ static int openInputDevice(lua_State *L) { /* generate event */ if(write(pipefd[1], &ev, sizeof(struct input_event)) == -1) { - break; + printf("Failed to generate event.\n"); } } - exit(0); /* cannot be reached?! */ + + status = pclose_noshell(&pclose_arg); + if (status == -1) { + err(EXIT_FAILURE, "pclose_noshell()"); + } else { + printf("Power slider event listener child exited with status %d.\n", status); + + if WIFEXITED(status) { + printf("Child exited normally with status: %d.\n", WEXITSTATUS(status)); + } + if WIFSIGNALED(status) { + printf("Child terminated by signal: %d.\n", WTERMSIG(status)); + } + } + + // We're done, go away :). + _exit(EXIT_SUCCESS); } else { + printf("Slider pipe close in slot %d [inputfd[fd]: %d].\n", fd, pipefd[0]); close(pipefd[1]); inputfds[fd] = pipefd[0]; slider_pid = childpid; + printf("slider_pid is: %d\n", (int)slider_pid); } } else { inputfds[fd] = open(inputdevice, O_RDONLY | O_NONBLOCK, 0); @@ -144,18 +192,26 @@ static int openInputDevice(lua_State *L) { } static int closeInputDevices(lua_State *L) { + printf("closeInputDevices(): BEGIN\n"); #ifndef EMULATE_READER - int i; + int i, ret; for(i=0; i usecs/1000) diff --git a/kpdfview.c b/kpdfview.c index d0003ae7f..08ec30283 100644 --- a/kpdfview.c +++ b/kpdfview.c @@ -15,9 +15,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include +#include +#include +#include #include #include -#include +#include #include #include @@ -39,7 +43,7 @@ lua_State *L; int main(int argc, char **argv) { - int i, err; + int i; if(argc < 2) { fprintf(stderr, "needs config file as first argument.\n"); @@ -79,6 +83,15 @@ int main(int argc, char **argv) { } } + /* Make popen_noshell & valgrind happy */ + if (fflush(stdout) != 0) + err(EXIT_FAILURE, "fflush(stdout)"); + if (fflush(stderr) != 0) + err(EXIT_FAILURE, "fflush(stderr)"); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + return 0; } diff --git a/launchpad/kpdf.sh b/launchpad/kpdf.sh index c1f81c700..3f5cffc43 100755 --- a/launchpad/kpdf.sh +++ b/launchpad/kpdf.sh @@ -31,7 +31,3 @@ fi # always try to continue cvm killall -cont cvm || /etc/init.d/framework start - -# cleanup hanging process -killall lipc-wait-event - diff --git a/popen-noshell/README b/popen-noshell/README new file mode 100644 index 000000000..7b829d130 --- /dev/null +++ b/popen-noshell/README @@ -0,0 +1,21 @@ +/* + * popen_noshell: A faster implementation of popen() and system() for Linux. + * Copyright (c) 2009 Ivan Zahariev (famzah) + * Version: 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +This is the faster popen() alternative implementation. + +Taken from http://code.google.com/p/popen-noshell/ diff --git a/popen-noshell/popen_noshell.c b/popen-noshell/popen_noshell.c new file mode 100644 index 000000000..ed37d07d5 --- /dev/null +++ b/popen-noshell/popen_noshell.c @@ -0,0 +1,550 @@ +/* + * popen_noshell: A faster implementation of popen() and system() for Linux. + * Copyright (c) 2009 Ivan Zahariev (famzah) + * Version: 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "popen_noshell.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Wish-list: + * 1) Make the "ignore_stderr" parameter a mode - ignore, leave unchanged, redirect to stdout (the last is not implemented yet) + * 2) Code a faster system(): system_noshell(), system_noshell_compat() + */ + +//#define POPEN_NOSHELL_DEBUG + +// because of C++, we can't call err() or errx() within the child, because they call exit(), and _exit() is what must be called; so we wrap +#define _ERR(EVAL, FMT, ...) \ + { \ + warn(FMT, ##__VA_ARGS__); \ + _exit(EVAL); \ + } +#define _ERRX(EVAL, FMT, ...) \ + { \ + warnx(FMT, ##__VA_ARGS__); \ + _exit(EVAL); \ + } + +int _popen_noshell_fork_mode = POPEN_NOSHELL_MODE_CLONE; + +void popen_noshell_set_fork_mode(int mode) { // see "popen_noshell.h" POPEN_NOSHELL_MODE_* constants + _popen_noshell_fork_mode = mode; +} + +int popen_noshell_reopen_fd_to_dev_null(int fd) { + int dev_null_fd; + + dev_null_fd = open("/dev/null", O_RDWR); + if (dev_null_fd < 0) return -1; + + if (close(fd) != 0) { + return -1; + } + if (dup2(dev_null_fd, fd) == -1) { + return -1; + } + if (close(dev_null_fd) != 0) { + return -1; + } + + return 0; +} + +int _popen_noshell_close_and_dup(int pipefd[2], int closed_pipefd, int target_fd) { + int dupped_pipefd; + + dupped_pipefd = (closed_pipefd == 0 ? 1 : 0); // get the FD of the other end of the pipe + + if (close(pipefd[closed_pipefd]) != 0) { + return -1; + } + + if (close(target_fd) != 0) { + return -1; + } + if (dup2(pipefd[dupped_pipefd], target_fd) == -1) { + return -1; + } + if (close(pipefd[dupped_pipefd]) != 0) { + return -1; + } + + return 0; +} + +void _pclose_noshell_free_clone_arg_memory(struct popen_noshell_clone_arg *func_args) { + char **cmd_argv; + + free((char *)func_args->file); + cmd_argv = (char **)func_args->argv; + while (*cmd_argv) { + free(*cmd_argv); + ++cmd_argv; + } + free((char **)func_args->argv); + free(func_args); +} + +void _popen_noshell_child_process( + /* We need the pointer *arg_ptr only to free whatever we reference if exec() fails and we were fork()'ed (thus memory was copied), + * not clone()'d */ + struct popen_noshell_clone_arg *arg_ptr, /* NULL if we were called by pure fork() (not because of Valgrind) */ + int pipefd_0, int pipefd_1, int read_pipe, int ignore_stderr, const char *file, const char * const *argv) { + + int closed_child_fd; + int closed_pipe_fd; + int dupped_child_fd; + int pipefd[2] = {pipefd_0, pipefd_1}; + + if (ignore_stderr) { /* ignore STDERR completely? */ + if (popen_noshell_reopen_fd_to_dev_null(STDERR_FILENO) != 0) _ERR(255, "popen_noshell_reopen_fd_to_dev_null(%d)", STDERR_FILENO); + } + + if (read_pipe) { + closed_child_fd = STDIN_FILENO; /* re-open STDIN to /dev/null */ + closed_pipe_fd = 0; /* close read end of pipe */ + dupped_child_fd = STDOUT_FILENO; /* dup the other pipe end to STDOUT */ + } else { + closed_child_fd = STDOUT_FILENO; /* ignore STDOUT completely */ + closed_pipe_fd = 1; /* close write end of pipe */ + dupped_child_fd = STDIN_FILENO; /* dup the other pipe end to STDIN */ + } + if (popen_noshell_reopen_fd_to_dev_null(closed_child_fd) != 0) { + _ERR(255, "popen_noshell_reopen_fd_to_dev_null(%d)", closed_child_fd); + } + if (_popen_noshell_close_and_dup(pipefd, closed_pipe_fd, dupped_child_fd) != 0) { + _ERR(255, "_popen_noshell_close_and_dup(%d ,%d)", closed_pipe_fd, dupped_child_fd); + } + + execvp(file, (char * const *)argv); + + /* if we are here, exec() failed */ + + warn("exec(\"%s\") inside the child", file); + +#ifdef POPEN_NOSHELL_VALGRIND_DEBUG + if (arg_ptr) { /* not NULL if we were called by clone() */ + /* but Valgrind does not support clone(), so we were actually called by fork(), thus memory was copied... */ + /* free this copied memory; if it was not Valgrind, this memory would have been shared and would belong to the parent! */ + _pclose_noshell_free_clone_arg_memory(arg_ptr); + } +#endif + + if (fflush(stdout) != 0) _ERR(255, "fflush(stdout)"); + if (fflush(stderr) != 0) _ERR(255, "fflush(stderr)"); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + _exit(255); // call _exit() and not exit(), or you'll have troubles in C++ +} + +int popen_noshell_child_process_by_clone(void *raw_arg) { + struct popen_noshell_clone_arg *arg; + + arg = (struct popen_noshell_clone_arg *)raw_arg; + _popen_noshell_child_process(arg, arg->pipefd_0, arg->pipefd_1, arg->read_pipe, arg->ignore_stderr, arg->file, arg->argv); + + return 0; +} + +char ** popen_noshell_copy_argv(const char * const *argv_orig) { + int size = 1; /* there is at least one NULL element */ + char **argv; + char **argv_new; + int n; + + argv = (char **) argv_orig; + while (*argv) { + ++size; + ++argv; + } + + argv_new = (char **)malloc(sizeof(char *) * size); + if (!argv_new) return NULL; + + argv = (char **)argv_orig; + n = 0; + while (*argv) { + argv_new[n] = strdup(*argv); + if (!argv_new[n]) return NULL; + ++argv; + ++n; + } + argv_new[n] = (char *)NULL; + + return argv_new; +} + +/* + * Similar to vfork() and threading. + * Starts a process which behaves like a thread (shares global variables in memory with the parent) but + * has a different PID and can call exec(), unlike traditional threads which are not allowed to call exec(). + * + * This fork function is very resource-light because it does not copy any memory from the parent, but shares it. + * + * Like standard threads, you have to provide a start function *fn and arguments to it *arg. The life of the + * new vmfork()'ed process starts from this function. + * + * After you have reaped the child via waitpid(), you have to free() the memory at "*memory_to_free_on_child_exit". + * + * When the *fn function returns, the child process terminates. The integer returned by *fn is the exit code for the child process. + * The child process may also terminate explicitly by calling exit(2) or after receiving a fatal signal. + * + * Returns -1 on error. On success returns the PID of the newly created child. + */ +pid_t popen_noshell_vmfork(int (*fn)(void *), void *arg, void **memory_to_free_on_child_exit) { + void *stack, *stack_aligned; + pid_t pid; + + stack = malloc(POPEN_NOSHELL_STACK_SIZE + 15); + if (!stack) return -1; + *memory_to_free_on_child_exit = stack; + + /* + * On all supported Linux platforms the stack grows down, except for HP-PARISC. + * You can grep the kernel source for "STACK_GROWSUP", in order to get this information. + */ + // stack grows down, set pointer at the end of the block + stack_aligned = (void *) ((char * /*byte*/)stack + POPEN_NOSHELL_STACK_SIZE/*bytes*/); + + /* + * On all supported platforms by GNU libc, the stack is aligned to 16 bytes, except for the SuperH platform which is aligned to 8 bytes. + * You can grep the glibc source for "STACK_ALIGN", in order to get this information. + */ + stack_aligned = (void *) ( ((uintptr_t)stack_aligned+15) & ~ 0x0F ); // align to 16 bytes + + /* + * Maybe we could have used posix_memalign() here... + * Our implementation seems a bit more portable though - I've read somewhere that posix_memalign() is not supported on all platforms. + * The above malloc() + align implementation is taken from: + * http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me + */ + +#ifndef POPEN_NOSHELL_VALGRIND_DEBUG + pid = clone(fn, stack_aligned, CLONE_VM | SIGCHLD, arg); +#else + pid = fork(); // Valgrind does not support arbitrary clone() calls, so we use fork for the tests +#endif + if (pid == -1) return -1; + + if (pid == 0) { // child +#ifdef POPEN_NOSHELL_VALGRIND_DEBUG + free(stack); // this is a copy because of the fork(), we are not using it at all + _exit(fn(arg)); // if we used fork() because of Valgrind, invoke the child function manually; always use _exit() +#endif + errx(EXIT_FAILURE, "This must never happen"); + } // child life ends here, for sure + + return pid; +} + +/* + * Pipe stream to or from process. Similar to popen(), only much faster. + * + * "file" is the command to be executed. It is searched within the PATH environment variable. + * "argv[]" is an array to "char *" elements which are passed as command-line arguments. + * Note: The first element must be the same string as "file". + * Note: The last element must be a (char *)NULL terminating element. + * "type" specifies if we are reading from the STDOUT or writing to the STDIN of the executed command "file". Use "r" for reading, "w" for writing. + * "pid" is a pointer to an interger. The PID of the child process is stored there. + * "ignore_stderr" has the following meaning: + * 0: leave STDERR of the child process attached to the current STDERR of the parent process + * 1: ignore the STDERR of the child process + * + * This function is not very sustainable on failures. This means that if it fails for some reason (out of memory, no such executable, etc.), + * you are probably in trouble, because the function allocated some memory or file descriptors and never released them. + * Normally, this function should never fail. + * + * Returns NULL on any error, "errno" is set appropriately. + * On success, a stream pointer is returned. + * When you are done working with the stream, you have to close it by calling pclose_noshell(), or else you will leave zombie processes. + */ +FILE *popen_noshell(const char *file, const char * const *argv, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg, int ignore_stderr) { + int read_pipe; + int pipefd[2]; // 0 -> READ, 1 -> WRITE ends + pid_t pid; + FILE *fp; + + memset(pclose_arg, 0, sizeof(struct popen_noshell_pass_to_pclose)); + + if (strcmp(type, "r") == 0) { + read_pipe = 1; + } else if (strcmp(type, "w") == 0) { + read_pipe = 0; + } else { + errno = EINVAL; + return NULL; + } + + if (pipe(pipefd) != 0) return NULL; + + if (_popen_noshell_fork_mode) { // use fork() + + pid = fork(); + if (pid == -1) return NULL; + if (pid == 0) { + _popen_noshell_child_process(NULL, pipefd[0], pipefd[1], read_pipe, ignore_stderr, file, argv); + errx(EXIT_FAILURE, "This must never happen"); + } // child life ends here, for sure + + } else { // use clone() + + struct popen_noshell_clone_arg *arg = NULL; + + arg = (struct popen_noshell_clone_arg*) malloc(sizeof(struct popen_noshell_clone_arg)); + if (!arg) return NULL; + + /* Copy memory structures, so that nobody can free() our memory while we use it in the child! */ + arg->pipefd_0 = pipefd[0]; + arg->pipefd_1 = pipefd[1]; + arg->read_pipe = read_pipe; + arg->ignore_stderr = ignore_stderr; + arg->file = strdup(file); + if (!arg->file) return NULL; + arg->argv = (const char * const *)popen_noshell_copy_argv(argv); + if (!arg->argv) return NULL; + + pclose_arg->free_clone_mem = 1; + pclose_arg->func_args = arg; + pclose_arg->stack = NULL; // we will populate it below + + pid = popen_noshell_vmfork(&popen_noshell_child_process_by_clone, arg, &(pclose_arg->stack)); + if (pid == -1) return NULL; + + } // done: using clone() + + /* parent process */ + + if (read_pipe) { + if (close(pipefd[1/*write*/]) != 0) return NULL; + fp = fdopen(pipefd[0/*read*/], "r"); + } else { // write_pipe + if (close(pipefd[0/*read*/]) != 0) return NULL; + fp = fdopen(pipefd[1/*write*/], "w"); + } + if (fp == NULL) { + return NULL; // fdopen() failed + } + + pclose_arg->fp = fp; + pclose_arg->pid = pid; + + return fp; // we should never end up here +} + +int popen_noshell_add_ptr_to_argv(char ***argv, int *count, char *start) { + *count += 1; + *argv = (char **) realloc(*argv, *count * sizeof(char **)); + if (*argv == NULL) { + return -1; + } + *(*argv + *count - 1) = start; + return 0; +} + +int _popen_noshell_add_token(char ***argv, int *count, char *start, char *command, int *j) { + if (start != NULL && command + *j - 1 - start >= 0) { + command[*j] = '\0'; // terminate the token in memory + *j += 1; +#ifdef POPEN_NOSHELL_DEBUG + printf("Token: %s\n", start); +#endif + if (popen_noshell_add_ptr_to_argv(argv, count, start) != 0) { + return -1; + } + } + return 0; +} + +#define _popen_noshell_split_return_NULL { if (argv != NULL) free(argv); if (command != NULL) free(command); return NULL; } +char ** popen_noshell_split_command_to_argv(const char *command_original, char **free_this_buf) { + char *command; + size_t i, len; + char *start = NULL; + char c; + char **argv = NULL; + int count = 0; + const char _popen_bash_meta_characters[] = "!\\$`\n|&;()<>"; + int in_sq = 0; + int in_dq = 0; + int j = 0; +#ifdef POPEN_NOSHELL_DEBUG + char **tmp; +#endif + + command = (char *)calloc(strlen(command_original) + 1, sizeof(char)); + if (!command) _popen_noshell_split_return_NULL; + + *free_this_buf = command; + + len = strlen(command_original); // get the original length + j = 0; + for (i = 0; i < len; ++i) { + if (!start) start = command + j; + c = command_original[i]; + + if (index(_popen_bash_meta_characters, c) != NULL) { + errno = EINVAL; + _popen_noshell_split_return_NULL; + } + + if (c == ' ' || c == '\t') { + if (in_sq || in_dq) { + command[j++] = c; + continue; + } + + // new token + if (_popen_noshell_add_token(&argv, &count, start, command, &j) != 0) { + _popen_noshell_split_return_NULL; + } + start = NULL; + continue; + } + + if (c == '\'' && !in_dq) { + in_sq = !in_sq; + continue; + } + if (c == '"' && !in_sq) { + in_dq = !in_dq; + continue; + } + + command[j++] = c; + } + if (in_sq || in_dq) { // unmatched single/double quote + errno = EINVAL; + _popen_noshell_split_return_NULL; + } + + if (_popen_noshell_add_token(&argv, &count, start, command, &j) != 0) { + _popen_noshell_split_return_NULL; + } + + if (count == 0) { + errno = EINVAL; + _popen_noshell_split_return_NULL; + } + + if (popen_noshell_add_ptr_to_argv(&argv, &count, NULL) != 0) { // NULL-terminate the list + _popen_noshell_split_return_NULL; + } + +#ifdef POPEN_NOSHELL_DEBUG + tmp = argv; + while (*tmp) { + printf("ARGV: |%s|\n", *tmp); + ++tmp; + } +#endif + + return argv; + + /* Example test strings: + "a'zz bb edd" + " abc ff " + " abc ff" + "' abc ff ' " + "" + " " + " '" + "ab\\c" + "ls -la /proc/self/fd 'z' 'ab'g'z\" zz' \" abc'd\" ' ab\"c def '" + */ +} + +/* + * Pipe stream to or from process. Similar to popen(), only much faster. + * + * This is simpler than popen_noshell() but is more INSECURE. + * Since shells have very complicated expansion, quoting and word splitting algorithms, we do NOT try to re-implement them here. + * This function does NOT support any special characters. It will immediately return an error if such symbols are encountered in "command". + * The "command" is split only by space and tab delimiters. The special symbols are pre-defined in _popen_bash_meta_characters[]. + * The only special characters supported are single and double quotes. You can enclose arguments in quotes and they should be splitted correctly. + * + * If possible, use popen_noshell() because of its better security. + * + * "command" is the command and its arguments to be executed. The command is searched within the PATH environment variable. + * The whole "command" string is parsed and splitted, so that it can be directly given to popen_noshell() and resp. to exec(). + * This parsing is very simple and may contain bugs (see above). If possible, use popen_noshell() directly. + * "type" specifies if we are reading from the STDOUT or writing to the STDIN of the executed command. Use "r" for reading, "w" for writing. + * "pid" is a pointer to an interger. The PID of the child process is stored there. + * + * Returns NULL on any error, "errno" is set appropriately. + * On success, a stream pointer is returned. + * When you are done working with the stream, you have to close it by calling pclose_noshell(), or else you will leave zombie processes. + */ +FILE *popen_noshell_compat(const char *command, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg) { + char **argv; + FILE *fp; + char *to_free; + + argv = popen_noshell_split_command_to_argv(command, &to_free); + if (!argv) { + if (to_free) free(to_free); + return NULL; + } + + fp = popen_noshell(argv[0], (const char * const *)argv, type, pclose_arg, 0); + + free(to_free); + free(argv); + + return fp; +} + +/* + * You have to call this function after you have done working with the FILE pointer "fp" returned by popen_noshell() or by popen_noshell_compat(). + * + * Returns -1 on any error, "errno" is set appropriately. + * Returns the "status" of the child process as returned by waitpid(). + */ +int pclose_noshell(struct popen_noshell_pass_to_pclose *arg) { + int status; + + if (fclose(arg->fp) != 0) { + return -1; + } + + if (waitpid(arg->pid, &status, 0) != arg->pid) { + return -1; + } + + if (arg->free_clone_mem) { + free(arg->stack); + _pclose_noshell_free_clone_arg_memory(arg->func_args); + } + + return status; +} diff --git a/popen-noshell/popen_noshell.h b/popen-noshell/popen_noshell.h new file mode 100644 index 000000000..a2eeb3c6e --- /dev/null +++ b/popen-noshell/popen_noshell.h @@ -0,0 +1,69 @@ +/* + * popen_noshell: A faster implementation of popen() and system() for Linux. + * Copyright (c) 2009 Ivan Zahariev (famzah) + * Version: 1.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef POPEN_NOSHELL_H +#define POPEN_NOSHELL_H + +#include +#include +#include + +/* stack for the child process before it does exec() */ +#define POPEN_NOSHELL_STACK_SIZE 8*1024*1024 /* currently most Linux distros set this to 8 MBytes */ + +/* constants to use with popen_noshell_set_fork_mode() */ +#define POPEN_NOSHELL_MODE_CLONE 0 /* default, faster */ +#define POPEN_NOSHELL_MODE_FORK 1 /* slower */ + +struct popen_noshell_clone_arg { + int pipefd_0; + int pipefd_1; + int read_pipe; + int ignore_stderr; + const char *file; + const char * const *argv; +}; + +struct popen_noshell_pass_to_pclose { + FILE *fp; + pid_t pid; + int free_clone_mem; + void *stack; + struct popen_noshell_clone_arg *func_args; +}; + +/*************************** + * PUBLIC FUNCTIONS FOLLOW * + ***************************/ + +/* this is the native function call */ +FILE *popen_noshell(const char *file, const char * const *argv, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg, int ignore_stderr); + +/* more insecure, but more compatible with popen() */ +FILE *popen_noshell_compat(const char *command, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg); + +/* call this when you have finished reading and writing from/to the child process */ +int pclose_noshell(struct popen_noshell_pass_to_pclose *arg); /* the pclose() equivalent */ + +/* this is the innovative faster vmfork() which shares memory with the parent and is very resource-light; see the source code for documentation */ +pid_t popen_noshell_vmfork(int (*fn)(void *), void *arg, void **memory_to_free_on_child_exit); + +/* used only for benchmarking purposes */ +void popen_noshell_set_fork_mode(int mode); + +#endif From 9fab02e33f8fd4f819b25d6a15e7164ef1343b99 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 02:25:08 +0200 Subject: [PATCH 03/19] Kill debug printf --- input.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/input.c b/input.c index 9176659f3..f8077f1f8 100644 --- a/input.c +++ b/input.c @@ -49,11 +49,9 @@ struct popen_noshell_pass_to_pclose pclose_arg; void slider_handler(int sig) { - int status; /* Kill lipc-wait-event properly on exit */ if(pclose_arg.pid != 0) { - status = kill(pclose_arg.pid, SIGTERM); - printf("[SIGTERM] kill returned %d\n", status); + kill(pclose_arg.pid, SIGTERM); } } @@ -77,8 +75,6 @@ static int openInputDevice(lua_State *L) { return luaL_error(L, "no free slot for new input device <%s>", inputdevice); } - printf("Opening input device <%s> in slot %d.\n", inputdevice, fd); - if(!strcmp("slider",inputdevice)) { /* special case: the power slider */ int pipefd[2]; @@ -106,7 +102,7 @@ static int openInputDevice(lua_State *L) { /* listen power slider events */ char *exec_file = "lipc-wait-event"; - char *arg1 = "-m"; // Hang for ever, don't exit on the first one, we're in a dedicated child, and we'll be closed on exit, so we don't care + char *arg1 = "-m"; // Hang for ever, don't exit on the first one: we're in a dedicated child, and we'll be killed/closed on exit, so we don't care char *arg2 = "-s"; char *arg3 = "0"; char *arg4 = "com.lab126.powerd"; @@ -123,8 +119,6 @@ static int openInputDevice(lua_State *L) { err(EXIT_FAILURE, "popen_noshell()"); } - printf("PID of our child is: %d (ours: %d)\n", (int)pclose_arg.pid, (int)getpid()); - while(fgets(std_out, sizeof(std_out)-1, fp)) { if(std_out[0] == 'g') { ev.code = CODE_IN_SAVER; @@ -167,11 +161,9 @@ static int openInputDevice(lua_State *L) { // We're done, go away :). _exit(EXIT_SUCCESS); } else { - printf("Slider pipe close in slot %d [inputfd[fd]: %d].\n", fd, pipefd[0]); close(pipefd[1]); inputfds[fd] = pipefd[0]; slider_pid = childpid; - printf("slider_pid is: %d\n", (int)slider_pid); } } else { inputfds[fd] = open(inputdevice, O_RDONLY | O_NONBLOCK, 0); @@ -192,26 +184,18 @@ static int openInputDevice(lua_State *L) { } static int closeInputDevices(lua_State *L) { - printf("closeInputDevices(): BEGIN\n"); #ifndef EMULATE_READER - int i, ret; + int i; for(i=0; i Date: Tue, 2 Oct 2012 03:11:16 +0200 Subject: [PATCH 04/19] Update the standalone testcase, too. --- .gitignore | 1 + Makefile | 7 ++++-- input.c | 1 - slider_watcher.c | 64 ++++++++++++++++++++++++++++++++++++------------ 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 7dbe43999..b498daf97 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ crash.log data fonts kpdfview +slider_watcher *.o kindlepdfviewer-*.zip diff --git a/Makefile b/Makefile index 551feef2b..586e5cf1e 100644 --- a/Makefile +++ b/Makefile @@ -121,8 +121,11 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o popen_noshell.o i $(LDFLAGS) \ -o kpdfview -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP) -slider_watcher: slider_watcher.c - $(CC) $(CFLAGS) $< -o $@ +slider_watcher.o: %.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + +slider_watcher: popen_noshell.o slider_watcher.o + $(CC) $(CFLAGS) popen_noshell.o slider_watcher.o -o $@ ft.o: %.o: %.c $(THIRDPARTYLIBS) $(CC) -c $(KPDFREADER_CFLAGS) -I$(FREETYPEDIR)/include -I$(MUPDFDIR)/fitz $< -o $@ diff --git a/input.c b/input.c index f8077f1f8..126f94a9c 100644 --- a/input.c +++ b/input.c @@ -33,7 +33,6 @@ #include "input.h" #include #include -#include #define CODE_IN_SAVER 10000 #define CODE_OUT_SAVER 10001 diff --git a/slider_watcher.c b/slider_watcher.c index 6a4e26e15..cca6827a5 100644 --- a/slider_watcher.c +++ b/slider_watcher.c @@ -16,8 +16,11 @@ along with this program. If not, see . */ -#include +#include "popen-noshell/popen_noshell.h" +#include #include +#include +#include #include #include #include @@ -25,18 +28,19 @@ #include #include #include +#include -#define OUTPUT_SIZE 21 -#define EVENT_PIPE "/tmp/event_slider" #define CODE_IN_SAVER 10000 #define CODE_OUT_SAVER 10001 int main ( int argc, char *argv[] ) { - int fd, ret; + int fd; FILE *fp; - char std_out[OUTPUT_SIZE] = ""; + char std_out[256]; + int status; + struct popen_noshell_pass_to_pclose pclose_arg; struct input_event ev; __u16 key_code = 10000; @@ -51,7 +55,7 @@ main ( int argc, char *argv[] ) /* open npipe for writing */ fd = open(argv[1], O_RDWR | O_NONBLOCK); if(fd < 0) { - printf("Open %s falied: %s\n", argv[1], strerror(errno)); + printf("Open %s failed: %s\n", argv[1], strerror(errno)); exit(EXIT_FAILURE); } @@ -60,15 +64,25 @@ main ( int argc, char *argv[] ) ev.code = key_code; ev.value = 1; - while(1) { - /* listen power slider events */ - memset(std_out, 0, OUTPUT_SIZE); - fp = popen("lipc-wait-event -s 0 com.lab126.powerd goingToScreenSaver,outOfScreenSaver", "r"); - ret = fread(std_out, OUTPUT_SIZE, 1, fp); - pclose(fp); + /* listen power slider events */ + char *exec_file = "lipc-wait-event"; + char *arg1 = "-m"; + char *arg2 = "-s"; + char *arg3 = "0"; + char *arg4 = "com.lab126.powerd"; + char *arg5 = "goingToScreenSaver,outOfScreenSaver"; + char *arg6 = (char *) NULL; + char *chargv[] = {exec_file, arg1, arg2, arg3, arg4, arg5, arg6}; + + fp = popen_noshell(exec_file, (const char * const *)chargv, "r", &pclose_arg, 0); + if (!fp) { + err(EXIT_FAILURE, "popen_noshell()"); + } + + while(fgets(std_out, sizeof(std_out)-1, fp)) { + + /* printf("Got line: %s", std_out); */ - /* fill event struct */ - gettimeofday(&ev.time, NULL); if(std_out[0] == 'g') { ev.code = CODE_IN_SAVER; } else if(std_out[0] == 'o') { @@ -77,9 +91,29 @@ main ( int argc, char *argv[] ) printf("Unrecognized event.\n"); exit(EXIT_FAILURE); } + /* fill event struct */ + gettimeofday(&ev.time, NULL); + + /* printf("Send event %d\n", ev.code); */ /* generate event */ - ret = write(fd, &ev, sizeof(struct input_event)); + if(write(fd, &ev, sizeof(struct input_event)) == -1) { + printf("Failed to generate event.\n"); + } + } + + status = pclose_noshell(&pclose_arg); + if (status == -1) { + err(EXIT_FAILURE, "pclose_noshell()"); + } else { + printf("Power slider event listener child exited with status %d.\n", status); + + if WIFEXITED(status) { + printf("Child exited normally with status: %d.\n", WEXITSTATUS(status)); + } + if WIFSIGNALED(status) { + printf("Child terminated by signal: %d.\n", WTERMSIG(status)); + } } close(fd); From 44f69b55cd8dced512debf370a74479f94bbc8de Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 03:29:31 +0200 Subject: [PATCH 05/19] Revert Makefile changes potentially unsuitable for upstream --- Makefile | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 586e5cf1e..76b4c97b7 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ TTF_FONTS_DIR=$(MUPDFDIR)/fonts # set this to your ARM cross compiler: -HOST:=arm-kindle-linux-gnueabi +HOST:=arm-none-linux-gnueabi CC:=$(HOST)-gcc CXX:=$(HOST)-g++ STRIP:=$(HOST)-strip @@ -29,14 +29,10 @@ endif HOSTCC:=gcc HOSTCXX:=g++ -# Base CFLAGS, without arch. Will use it as-is for luajit, because its buildsystem picks up the wrong flags, possibly from my env... -BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer -fno-stack-protector -U_FORTIFY_SOURCE - -CFLAGS:=$(BASE_CFLAGS) -CXXFLAGS:=$(BASE_CFLAGS) -fno-use-cxa-atexit +CFLAGS:=-O3 $(SYSROOT) +CXXFLAGS:=-O3 $(SYSROOT) LDFLAGS:=-Wl,-O1 -Wl,--as-needed ARM_CFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp -HOSTCFLAGS:=-O2 -march=native -ffast-math -pipe -fomit-frame-pointer # use this for debugging: #CFLAGS:=-O0 -g @@ -173,7 +169,7 @@ clean: -rm -f *.o kpdfview slider_watcher cleanthirdparty: - -make -C $(LUADIR) clean CFLAGS="" + -make -C $(LUADIR) clean -make -C $(MUPDFDIR) build="release" clean -make -C $(CRENGINEDIR)/thirdparty/antiword clean test -d $(CRENGINEDIR)/thirdparty/chmlib && make -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found @@ -185,12 +181,12 @@ cleanthirdparty: -rm -f $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.host: - make -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/fontdump + make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump cp -a $(MUPDFLIBDIR)/fontdump $(MUPDFDIR)/fontdump.host make -C mupdf clean $(MUPDFDIR)/cmapdump.host: - make -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/cmapdump + make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump cp -a $(MUPDFLIBDIR)/cmapdump $(MUPDFDIR)/cmapdump.host make -C mupdf clean @@ -216,7 +212,7 @@ $(LUALIB): ifdef EMULATE_READER make -C $(LUADIR) else - make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(BASE_CFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(HOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" V=1 + make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(HOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" endif thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) From 8e7f4ba989545445977588822b0be1e3da154d4d Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 23:10:55 +0200 Subject: [PATCH 06/19] Add a small makefile to build popen_noshell as a static lib --- .gitignore | 3 +++ popen-noshell/Makefile | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 popen-noshell/Makefile diff --git a/.gitignore b/.gitignore index b498daf97..c806532dd 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ kpvcrlib/CMakeCache.txt kpvcrlib/CMakeFiles/ kpvcrlib/cmake_install.cmake kpvcrlib/Makefile + +popen-noshell/libpopen_noshell.a +popen-noshell/*.o diff --git a/popen-noshell/Makefile b/popen-noshell/Makefile new file mode 100644 index 000000000..8fc6d1ef5 --- /dev/null +++ b/popen-noshell/Makefile @@ -0,0 +1,15 @@ +SRCS=popen_noshell.c + +OBJS:=$(SRCS:%.c=%.o) + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< + +all: libpopen_noshell.a + +libpopen_noshell.a: $(OBJS) + $(AR) rcs $@ $(OBJS) + +clean: + rm -rf *.o + rm -rf libpopen_noshell.a \ No newline at end of file From 3f5fe1e991181fdafbb6114f605a86ad163ae3ca Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 23:18:28 +0200 Subject: [PATCH 07/19] Use popen_noshell as a static lib instead of an object file. Use CHOST instead of HOST (and allow it to be set from the env), use $(MAKE) instead of make to allow using the jobserver properly, and remove the dash from commands where we do care about the return code (or inhibit errors the usual way: rm -f instead of -rm) --- Makefile | 82 ++++++++++++++++++++++-------------------- popen-noshell/Makefile | 2 +- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 76b4c97b7..e2aa38226 100644 --- a/Makefile +++ b/Makefile @@ -18,10 +18,11 @@ TTF_FONTS_DIR=$(MUPDFDIR)/fonts # set this to your ARM cross compiler: -HOST:=arm-none-linux-gnueabi -CC:=$(HOST)-gcc -CXX:=$(HOST)-g++ -STRIP:=$(HOST)-strip +CHOST?=arm-none-linux-gnueabi +CC:=$(CHOST)-gcc +CXX:=$(CHOST)-g++ +STRIP:=$(CHOST)-strip +STRIP:=$(CHOST)-ar ifdef SBOX_UNAME_MACHINE CC:=gcc CXX:=g++ @@ -90,9 +91,11 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ LUALIB := $(LUADIR)/src/libluajit.a -all:kpdfview +POPENNSLIB := $(POPENNSDIR)/libpopen_noshell.a -kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o popen_noshell.o input.o util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) +all: kpdfview + +kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) $(CC) \ $(CFLAGS) \ kpdfview.o \ @@ -100,8 +103,8 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o popen_noshell.o i pdf.o \ blitbuffer.o \ drawcontext.o \ - popen_noshell.o \ input.o \ + $(POPENNSLIB) \ util.o \ ft.o \ lfs.o \ @@ -120,8 +123,8 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o popen_noshell.o i slider_watcher.o: %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ -slider_watcher: popen_noshell.o slider_watcher.o - $(CC) $(CFLAGS) popen_noshell.o slider_watcher.o -o $@ +slider_watcher: slider_watcher.o $(POPENNSLIB) + $(CC) $(CFLAGS) slider_watcher.o $(POPENNSLIB) -o $@ ft.o: %.o: %.c $(THIRDPARTYLIBS) $(CC) -c $(KPDFREADER_CFLAGS) -I$(FREETYPEDIR)/include -I$(MUPDFDIR)/fitz $< -o $@ @@ -138,11 +141,8 @@ cre.o: %.o: %.cpp lfs.o: $(LFSDIR)/src/lfs.c $(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@ -popen_noshell.o: $(POPENNSDIR)/popen_noshell.c - $(CC) -c $(CFLAGS) -I$(POPENNSDIR) $(POPENNSDIR)/popen_noshell.c -o $@ - fetchthirdparty: - -rm -Rf mupdf/thirdparty + rm -rf mupdf/thirdparty test -d mupdf && (cd mupdf; git checkout .) || echo warn: mupdf folder not found test -d $(LUADIR) && (cd $(LUADIR); git checkout .) || echo warn: $(LUADIR) folder not found git submodule init @@ -166,56 +166,60 @@ fetchthirdparty: cd mupdf && patch -N -p1 < ../mupdf.patch clean: - -rm -f *.o kpdfview slider_watcher + rm -f *.o kpdfview slider_watcher cleanthirdparty: - -make -C $(LUADIR) clean - -make -C $(MUPDFDIR) build="release" clean - -make -C $(CRENGINEDIR)/thirdparty/antiword clean - test -d $(CRENGINEDIR)/thirdparty/chmlib && make -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found - test -d $(CRENGINEDIR)/thirdparty/libpng && (make -C $(CRENGINEDIR)/thirdparty/libpng clean) || echo warn: chmlib folder not found - test -d $(CRENGINEDIR)/crengine && (make -C $(CRENGINEDIR)/crengine clean) || echo warn: chmlib folder not found - test -d $(KPVCRLIBDIR) && (make -C $(KPVCRLIBDIR) clean) || echo warn: chmlib folder not found - -rm -rf $(DJVUDIR)/build - -rm -f $(MUPDFDIR)/fontdump.host - -rm -f $(MUPDFDIR)/cmapdump.host + $(MAKE) -C $(LUADIR) clean + $(MAKE) -C $(MUPDFDIR) build="release" clean + $(MAKE) -C $(CRENGINEDIR)/thirdparty/antiword clean + test -d $(CRENGINEDIR)/thirdparty/chmlib && $(MAKE) -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found + test -d $(CRENGINEDIR)/thirdparty/libpng && ($(MAKE) -C $(CRENGINEDIR)/thirdparty/libpng clean) || echo warn: chmlib folder not found + test -d $(CRENGINEDIR)/crengine && ($(MAKE) -C $(CRENGINEDIR)/crengine clean) || echo warn: chmlib folder not found + test -d $(KPVCRLIBDIR) && ($(MAKE) -C $(KPVCRLIBDIR) clean) || echo warn: chmlib folder not found + rm -rf $(DJVUDIR)/build + rm -f $(MUPDFDIR)/fontdump.host + rm -f $(MUPDFDIR)/cmapdump.host + $(MAKE) -C $(POPENNSDIR) clean $(MUPDFDIR)/fontdump.host: - make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump + $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump cp -a $(MUPDFLIBDIR)/fontdump $(MUPDFDIR)/fontdump.host - make -C mupdf clean + $(MAKE) -C mupdf clean $(MUPDFDIR)/cmapdump.host: - make -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump + $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump cp -a $(MUPDFLIBDIR)/cmapdump $(MUPDFDIR)/cmapdump.host - make -C mupdf clean + $(MAKE) -C mupdf clean $(MUPDFLIBS) $(THIRDPARTYLIBS): $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.host # build only thirdparty libs, libfitz and pdf utils, which will care for libmupdf.a being built - CFLAGS="$(CFLAGS) -DNOBUILTINFONT" make -C mupdf build="release" CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1 + CFLAGS="$(CFLAGS) -DNOBUILTINFONT" $(MAKE) -C mupdf build="release" CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= MU_APPS= BUSY_APP= XPS_APPS= verbose=1 $(DJVULIBS): - -mkdir $(DJVUDIR)/build + mkdir -p $(DJVUDIR)/build ifdef EMULATE_READER cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --disable-xmltools --disable-largefile else - cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --host=$(HOST) --disable-xmltools --disable-largefile + cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --host=$(CHOST) --disable-xmltools --disable-largefile endif - make -C $(DJVUDIR)/build + $(MAKE) -C $(DJVUDIR)/build $(CRENGINELIBS): cd $(KPVCRLIBDIR) && rm -rf CMakeCache.txt CMakeFiles && \ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS)" cmake . && \ - make + $(MAKE) $(LUALIB): ifdef EMULATE_READER - make -C $(LUADIR) + $(MAKE) -C $(LUADIR) else - make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(HOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" + $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(CHOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" endif -thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) +$(POPENNSLIB): + $(MAKE) -C $(POPENNSDIR) CC="$(CC)" AR="$(AR)" + +thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) $(POPENNSLIB) INSTALL_DIR=kindlepdfviewer @@ -226,8 +230,8 @@ customupdate: all # ensure that build binary is for ARM file kpdfview | grep ARM || exit 1 $(STRIP) --strip-unneeded kpdfview - -rm kindlepdfviewer-$(VERSION).zip - rm -Rf $(INSTALL_DIR) + rm -f kindlepdfviewer-$(VERSION).zip + rm -rf $(INSTALL_DIR) mkdir -p $(INSTALL_DIR)/{history,screenshots} echo $(VERSION) > $(INSTALL_DIR)/git-rev cp -p README.md COPYING kpdfview $(LUA_FILES) $(INSTALL_DIR) @@ -237,5 +241,5 @@ customupdate: all cp -r resources $(INSTALL_DIR) mkdir $(INSTALL_DIR)/fonts/host zip -9 -r kindlepdfviewer-$(VERSION).zip $(INSTALL_DIR) launchpad/ kite/ - rm -Rf $(INSTALL_DIR) + rm -rf $(INSTALL_DIR) @echo "copy kindlepdfviewer-$(VERSION).zip to /mnt/us/customupdates and install with shift+shift+I" diff --git a/popen-noshell/Makefile b/popen-noshell/Makefile index 8fc6d1ef5..facd99021 100644 --- a/popen-noshell/Makefile +++ b/popen-noshell/Makefile @@ -12,4 +12,4 @@ libpopen_noshell.a: $(OBJS) clean: rm -rf *.o - rm -rf libpopen_noshell.a \ No newline at end of file + rm -rf libpopen_noshell.a From 4e861715e3e9f7cafa98896004bd2a4c2bbfc86a Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 23:21:14 +0200 Subject: [PATCH 08/19] Fix a stupid typo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e2aa38226..7226dbf26 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ CHOST?=arm-none-linux-gnueabi CC:=$(CHOST)-gcc CXX:=$(CHOST)-g++ STRIP:=$(CHOST)-strip -STRIP:=$(CHOST)-ar +AR:=$(CHOST)-ar ifdef SBOX_UNAME_MACHINE CC:=gcc CXX:=g++ From 5c76ef0f78840a86b53a9d4185e087dbc7a1d826 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 23:30:12 +0200 Subject: [PATCH 09/19] Fetch popen_noshell during fetchthirdparty, don't bundle it in our repo --- Makefile | 3 + popen-noshell/Makefile | 15 - popen-noshell/README | 21 - popen-noshell/popen_noshell-buildfix.patch | 84 ++++ popen-noshell/popen_noshell.c | 550 --------------------- popen-noshell/popen_noshell.h | 69 --- 6 files changed, 87 insertions(+), 655 deletions(-) delete mode 100644 popen-noshell/Makefile delete mode 100644 popen-noshell/README create mode 100644 popen-noshell/popen_noshell-buildfix.patch delete mode 100644 popen-noshell/popen_noshell.c delete mode 100644 popen-noshell/popen_noshell.h diff --git a/Makefile b/Makefile index 7226dbf26..7a6ce5722 100644 --- a/Makefile +++ b/Makefile @@ -164,6 +164,9 @@ fetchthirdparty: patch -N -p0 < ../../../kpvcrlib/jpeg_decompress_struct_size.patch # MuPDF patch: use external fonts cd mupdf && patch -N -p1 < ../mupdf.patch + svn co http://popen-noshell.googlecode.com/svn/trunk/ popen-noshell + # popen_noshell patch: Make it build on recent TCs, and implement a simple Makefile for building it as a static lib + cd popen-noshell && patch -N -p0 < popen_noshell-buildfix.patch clean: rm -f *.o kpdfview slider_watcher diff --git a/popen-noshell/Makefile b/popen-noshell/Makefile deleted file mode 100644 index facd99021..000000000 --- a/popen-noshell/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -SRCS=popen_noshell.c - -OBJS:=$(SRCS:%.c=%.o) - -%.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< - -all: libpopen_noshell.a - -libpopen_noshell.a: $(OBJS) - $(AR) rcs $@ $(OBJS) - -clean: - rm -rf *.o - rm -rf libpopen_noshell.a diff --git a/popen-noshell/README b/popen-noshell/README deleted file mode 100644 index 7b829d130..000000000 --- a/popen-noshell/README +++ /dev/null @@ -1,21 +0,0 @@ -/* - * popen_noshell: A faster implementation of popen() and system() for Linux. - * Copyright (c) 2009 Ivan Zahariev (famzah) - * Version: 1.0 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -This is the faster popen() alternative implementation. - -Taken from http://code.google.com/p/popen-noshell/ diff --git a/popen-noshell/popen_noshell-buildfix.patch b/popen-noshell/popen_noshell-buildfix.patch new file mode 100644 index 000000000..6f9ba1bf8 --- /dev/null +++ b/popen-noshell/popen_noshell-buildfix.patch @@ -0,0 +1,84 @@ +Index: CREDITS +=================================================================== +--- CREDITS (revision 0) ++++ CREDITS (working copy) +@@ -0,0 +1 @@ ++Taken from http://code.google.com/p/popen-noshell/ + +Property changes on: CREDITS +___________________________________________________________________ +Added: svn:keywords +## -0,0 +1 ## ++Id +\ No newline at end of property +Index: Makefile +=================================================================== +--- Makefile (revision 0) ++++ Makefile (working copy) +@@ -0,0 +1,15 @@ ++SRCS=popen_noshell.c ++ ++OBJS:=$(SRCS:%.c=%.o) ++ ++%.o: %.c ++ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< ++ ++all: libpopen_noshell.a ++ ++libpopen_noshell.a: $(OBJS) ++ $(AR) rcs $@ $(OBJS) ++ ++clean: ++ rm -rf *.o ++ rm -rf libpopen_noshell.a + +Property changes on: Makefile +___________________________________________________________________ +Added: svn:keywords +## -0,0 +1 ## ++Id +\ No newline at end of property +Index: popen_noshell.c +=================================================================== +--- popen_noshell.c (revision 8) ++++ popen_noshell.c (working copy) +@@ -16,6 +16,10 @@ + * along with this program. If not, see . + */ + ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++ + #include "popen_noshell.h" + #include + #include +@@ -28,10 +32,6 @@ + #include + #include + #include +- +-#ifndef _GNU_SOURCE +-#define _GNU_SOURCE +-#endif + #include + + /* +@@ -249,7 +249,7 @@ + * The above malloc() + align implementation is taken from: + * http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me + */ +- ++ + #ifndef POPEN_NOSHELL_VALGRIND_DEBUG + pid = clone(fn, stack_aligned, CLONE_VM | SIGCHLD, arg); + #else +@@ -358,7 +358,7 @@ + + pclose_arg->fp = fp; + pclose_arg->pid = pid; +- ++ + return fp; // we should never end up here + } + diff --git a/popen-noshell/popen_noshell.c b/popen-noshell/popen_noshell.c deleted file mode 100644 index ed37d07d5..000000000 --- a/popen-noshell/popen_noshell.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * popen_noshell: A faster implementation of popen() and system() for Linux. - * Copyright (c) 2009 Ivan Zahariev (famzah) - * Version: 1.0 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include "popen_noshell.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Wish-list: - * 1) Make the "ignore_stderr" parameter a mode - ignore, leave unchanged, redirect to stdout (the last is not implemented yet) - * 2) Code a faster system(): system_noshell(), system_noshell_compat() - */ - -//#define POPEN_NOSHELL_DEBUG - -// because of C++, we can't call err() or errx() within the child, because they call exit(), and _exit() is what must be called; so we wrap -#define _ERR(EVAL, FMT, ...) \ - { \ - warn(FMT, ##__VA_ARGS__); \ - _exit(EVAL); \ - } -#define _ERRX(EVAL, FMT, ...) \ - { \ - warnx(FMT, ##__VA_ARGS__); \ - _exit(EVAL); \ - } - -int _popen_noshell_fork_mode = POPEN_NOSHELL_MODE_CLONE; - -void popen_noshell_set_fork_mode(int mode) { // see "popen_noshell.h" POPEN_NOSHELL_MODE_* constants - _popen_noshell_fork_mode = mode; -} - -int popen_noshell_reopen_fd_to_dev_null(int fd) { - int dev_null_fd; - - dev_null_fd = open("/dev/null", O_RDWR); - if (dev_null_fd < 0) return -1; - - if (close(fd) != 0) { - return -1; - } - if (dup2(dev_null_fd, fd) == -1) { - return -1; - } - if (close(dev_null_fd) != 0) { - return -1; - } - - return 0; -} - -int _popen_noshell_close_and_dup(int pipefd[2], int closed_pipefd, int target_fd) { - int dupped_pipefd; - - dupped_pipefd = (closed_pipefd == 0 ? 1 : 0); // get the FD of the other end of the pipe - - if (close(pipefd[closed_pipefd]) != 0) { - return -1; - } - - if (close(target_fd) != 0) { - return -1; - } - if (dup2(pipefd[dupped_pipefd], target_fd) == -1) { - return -1; - } - if (close(pipefd[dupped_pipefd]) != 0) { - return -1; - } - - return 0; -} - -void _pclose_noshell_free_clone_arg_memory(struct popen_noshell_clone_arg *func_args) { - char **cmd_argv; - - free((char *)func_args->file); - cmd_argv = (char **)func_args->argv; - while (*cmd_argv) { - free(*cmd_argv); - ++cmd_argv; - } - free((char **)func_args->argv); - free(func_args); -} - -void _popen_noshell_child_process( - /* We need the pointer *arg_ptr only to free whatever we reference if exec() fails and we were fork()'ed (thus memory was copied), - * not clone()'d */ - struct popen_noshell_clone_arg *arg_ptr, /* NULL if we were called by pure fork() (not because of Valgrind) */ - int pipefd_0, int pipefd_1, int read_pipe, int ignore_stderr, const char *file, const char * const *argv) { - - int closed_child_fd; - int closed_pipe_fd; - int dupped_child_fd; - int pipefd[2] = {pipefd_0, pipefd_1}; - - if (ignore_stderr) { /* ignore STDERR completely? */ - if (popen_noshell_reopen_fd_to_dev_null(STDERR_FILENO) != 0) _ERR(255, "popen_noshell_reopen_fd_to_dev_null(%d)", STDERR_FILENO); - } - - if (read_pipe) { - closed_child_fd = STDIN_FILENO; /* re-open STDIN to /dev/null */ - closed_pipe_fd = 0; /* close read end of pipe */ - dupped_child_fd = STDOUT_FILENO; /* dup the other pipe end to STDOUT */ - } else { - closed_child_fd = STDOUT_FILENO; /* ignore STDOUT completely */ - closed_pipe_fd = 1; /* close write end of pipe */ - dupped_child_fd = STDIN_FILENO; /* dup the other pipe end to STDIN */ - } - if (popen_noshell_reopen_fd_to_dev_null(closed_child_fd) != 0) { - _ERR(255, "popen_noshell_reopen_fd_to_dev_null(%d)", closed_child_fd); - } - if (_popen_noshell_close_and_dup(pipefd, closed_pipe_fd, dupped_child_fd) != 0) { - _ERR(255, "_popen_noshell_close_and_dup(%d ,%d)", closed_pipe_fd, dupped_child_fd); - } - - execvp(file, (char * const *)argv); - - /* if we are here, exec() failed */ - - warn("exec(\"%s\") inside the child", file); - -#ifdef POPEN_NOSHELL_VALGRIND_DEBUG - if (arg_ptr) { /* not NULL if we were called by clone() */ - /* but Valgrind does not support clone(), so we were actually called by fork(), thus memory was copied... */ - /* free this copied memory; if it was not Valgrind, this memory would have been shared and would belong to the parent! */ - _pclose_noshell_free_clone_arg_memory(arg_ptr); - } -#endif - - if (fflush(stdout) != 0) _ERR(255, "fflush(stdout)"); - if (fflush(stderr) != 0) _ERR(255, "fflush(stderr)"); - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - - _exit(255); // call _exit() and not exit(), or you'll have troubles in C++ -} - -int popen_noshell_child_process_by_clone(void *raw_arg) { - struct popen_noshell_clone_arg *arg; - - arg = (struct popen_noshell_clone_arg *)raw_arg; - _popen_noshell_child_process(arg, arg->pipefd_0, arg->pipefd_1, arg->read_pipe, arg->ignore_stderr, arg->file, arg->argv); - - return 0; -} - -char ** popen_noshell_copy_argv(const char * const *argv_orig) { - int size = 1; /* there is at least one NULL element */ - char **argv; - char **argv_new; - int n; - - argv = (char **) argv_orig; - while (*argv) { - ++size; - ++argv; - } - - argv_new = (char **)malloc(sizeof(char *) * size); - if (!argv_new) return NULL; - - argv = (char **)argv_orig; - n = 0; - while (*argv) { - argv_new[n] = strdup(*argv); - if (!argv_new[n]) return NULL; - ++argv; - ++n; - } - argv_new[n] = (char *)NULL; - - return argv_new; -} - -/* - * Similar to vfork() and threading. - * Starts a process which behaves like a thread (shares global variables in memory with the parent) but - * has a different PID and can call exec(), unlike traditional threads which are not allowed to call exec(). - * - * This fork function is very resource-light because it does not copy any memory from the parent, but shares it. - * - * Like standard threads, you have to provide a start function *fn and arguments to it *arg. The life of the - * new vmfork()'ed process starts from this function. - * - * After you have reaped the child via waitpid(), you have to free() the memory at "*memory_to_free_on_child_exit". - * - * When the *fn function returns, the child process terminates. The integer returned by *fn is the exit code for the child process. - * The child process may also terminate explicitly by calling exit(2) or after receiving a fatal signal. - * - * Returns -1 on error. On success returns the PID of the newly created child. - */ -pid_t popen_noshell_vmfork(int (*fn)(void *), void *arg, void **memory_to_free_on_child_exit) { - void *stack, *stack_aligned; - pid_t pid; - - stack = malloc(POPEN_NOSHELL_STACK_SIZE + 15); - if (!stack) return -1; - *memory_to_free_on_child_exit = stack; - - /* - * On all supported Linux platforms the stack grows down, except for HP-PARISC. - * You can grep the kernel source for "STACK_GROWSUP", in order to get this information. - */ - // stack grows down, set pointer at the end of the block - stack_aligned = (void *) ((char * /*byte*/)stack + POPEN_NOSHELL_STACK_SIZE/*bytes*/); - - /* - * On all supported platforms by GNU libc, the stack is aligned to 16 bytes, except for the SuperH platform which is aligned to 8 bytes. - * You can grep the glibc source for "STACK_ALIGN", in order to get this information. - */ - stack_aligned = (void *) ( ((uintptr_t)stack_aligned+15) & ~ 0x0F ); // align to 16 bytes - - /* - * Maybe we could have used posix_memalign() here... - * Our implementation seems a bit more portable though - I've read somewhere that posix_memalign() is not supported on all platforms. - * The above malloc() + align implementation is taken from: - * http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me - */ - -#ifndef POPEN_NOSHELL_VALGRIND_DEBUG - pid = clone(fn, stack_aligned, CLONE_VM | SIGCHLD, arg); -#else - pid = fork(); // Valgrind does not support arbitrary clone() calls, so we use fork for the tests -#endif - if (pid == -1) return -1; - - if (pid == 0) { // child -#ifdef POPEN_NOSHELL_VALGRIND_DEBUG - free(stack); // this is a copy because of the fork(), we are not using it at all - _exit(fn(arg)); // if we used fork() because of Valgrind, invoke the child function manually; always use _exit() -#endif - errx(EXIT_FAILURE, "This must never happen"); - } // child life ends here, for sure - - return pid; -} - -/* - * Pipe stream to or from process. Similar to popen(), only much faster. - * - * "file" is the command to be executed. It is searched within the PATH environment variable. - * "argv[]" is an array to "char *" elements which are passed as command-line arguments. - * Note: The first element must be the same string as "file". - * Note: The last element must be a (char *)NULL terminating element. - * "type" specifies if we are reading from the STDOUT or writing to the STDIN of the executed command "file". Use "r" for reading, "w" for writing. - * "pid" is a pointer to an interger. The PID of the child process is stored there. - * "ignore_stderr" has the following meaning: - * 0: leave STDERR of the child process attached to the current STDERR of the parent process - * 1: ignore the STDERR of the child process - * - * This function is not very sustainable on failures. This means that if it fails for some reason (out of memory, no such executable, etc.), - * you are probably in trouble, because the function allocated some memory or file descriptors and never released them. - * Normally, this function should never fail. - * - * Returns NULL on any error, "errno" is set appropriately. - * On success, a stream pointer is returned. - * When you are done working with the stream, you have to close it by calling pclose_noshell(), or else you will leave zombie processes. - */ -FILE *popen_noshell(const char *file, const char * const *argv, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg, int ignore_stderr) { - int read_pipe; - int pipefd[2]; // 0 -> READ, 1 -> WRITE ends - pid_t pid; - FILE *fp; - - memset(pclose_arg, 0, sizeof(struct popen_noshell_pass_to_pclose)); - - if (strcmp(type, "r") == 0) { - read_pipe = 1; - } else if (strcmp(type, "w") == 0) { - read_pipe = 0; - } else { - errno = EINVAL; - return NULL; - } - - if (pipe(pipefd) != 0) return NULL; - - if (_popen_noshell_fork_mode) { // use fork() - - pid = fork(); - if (pid == -1) return NULL; - if (pid == 0) { - _popen_noshell_child_process(NULL, pipefd[0], pipefd[1], read_pipe, ignore_stderr, file, argv); - errx(EXIT_FAILURE, "This must never happen"); - } // child life ends here, for sure - - } else { // use clone() - - struct popen_noshell_clone_arg *arg = NULL; - - arg = (struct popen_noshell_clone_arg*) malloc(sizeof(struct popen_noshell_clone_arg)); - if (!arg) return NULL; - - /* Copy memory structures, so that nobody can free() our memory while we use it in the child! */ - arg->pipefd_0 = pipefd[0]; - arg->pipefd_1 = pipefd[1]; - arg->read_pipe = read_pipe; - arg->ignore_stderr = ignore_stderr; - arg->file = strdup(file); - if (!arg->file) return NULL; - arg->argv = (const char * const *)popen_noshell_copy_argv(argv); - if (!arg->argv) return NULL; - - pclose_arg->free_clone_mem = 1; - pclose_arg->func_args = arg; - pclose_arg->stack = NULL; // we will populate it below - - pid = popen_noshell_vmfork(&popen_noshell_child_process_by_clone, arg, &(pclose_arg->stack)); - if (pid == -1) return NULL; - - } // done: using clone() - - /* parent process */ - - if (read_pipe) { - if (close(pipefd[1/*write*/]) != 0) return NULL; - fp = fdopen(pipefd[0/*read*/], "r"); - } else { // write_pipe - if (close(pipefd[0/*read*/]) != 0) return NULL; - fp = fdopen(pipefd[1/*write*/], "w"); - } - if (fp == NULL) { - return NULL; // fdopen() failed - } - - pclose_arg->fp = fp; - pclose_arg->pid = pid; - - return fp; // we should never end up here -} - -int popen_noshell_add_ptr_to_argv(char ***argv, int *count, char *start) { - *count += 1; - *argv = (char **) realloc(*argv, *count * sizeof(char **)); - if (*argv == NULL) { - return -1; - } - *(*argv + *count - 1) = start; - return 0; -} - -int _popen_noshell_add_token(char ***argv, int *count, char *start, char *command, int *j) { - if (start != NULL && command + *j - 1 - start >= 0) { - command[*j] = '\0'; // terminate the token in memory - *j += 1; -#ifdef POPEN_NOSHELL_DEBUG - printf("Token: %s\n", start); -#endif - if (popen_noshell_add_ptr_to_argv(argv, count, start) != 0) { - return -1; - } - } - return 0; -} - -#define _popen_noshell_split_return_NULL { if (argv != NULL) free(argv); if (command != NULL) free(command); return NULL; } -char ** popen_noshell_split_command_to_argv(const char *command_original, char **free_this_buf) { - char *command; - size_t i, len; - char *start = NULL; - char c; - char **argv = NULL; - int count = 0; - const char _popen_bash_meta_characters[] = "!\\$`\n|&;()<>"; - int in_sq = 0; - int in_dq = 0; - int j = 0; -#ifdef POPEN_NOSHELL_DEBUG - char **tmp; -#endif - - command = (char *)calloc(strlen(command_original) + 1, sizeof(char)); - if (!command) _popen_noshell_split_return_NULL; - - *free_this_buf = command; - - len = strlen(command_original); // get the original length - j = 0; - for (i = 0; i < len; ++i) { - if (!start) start = command + j; - c = command_original[i]; - - if (index(_popen_bash_meta_characters, c) != NULL) { - errno = EINVAL; - _popen_noshell_split_return_NULL; - } - - if (c == ' ' || c == '\t') { - if (in_sq || in_dq) { - command[j++] = c; - continue; - } - - // new token - if (_popen_noshell_add_token(&argv, &count, start, command, &j) != 0) { - _popen_noshell_split_return_NULL; - } - start = NULL; - continue; - } - - if (c == '\'' && !in_dq) { - in_sq = !in_sq; - continue; - } - if (c == '"' && !in_sq) { - in_dq = !in_dq; - continue; - } - - command[j++] = c; - } - if (in_sq || in_dq) { // unmatched single/double quote - errno = EINVAL; - _popen_noshell_split_return_NULL; - } - - if (_popen_noshell_add_token(&argv, &count, start, command, &j) != 0) { - _popen_noshell_split_return_NULL; - } - - if (count == 0) { - errno = EINVAL; - _popen_noshell_split_return_NULL; - } - - if (popen_noshell_add_ptr_to_argv(&argv, &count, NULL) != 0) { // NULL-terminate the list - _popen_noshell_split_return_NULL; - } - -#ifdef POPEN_NOSHELL_DEBUG - tmp = argv; - while (*tmp) { - printf("ARGV: |%s|\n", *tmp); - ++tmp; - } -#endif - - return argv; - - /* Example test strings: - "a'zz bb edd" - " abc ff " - " abc ff" - "' abc ff ' " - "" - " " - " '" - "ab\\c" - "ls -la /proc/self/fd 'z' 'ab'g'z\" zz' \" abc'd\" ' ab\"c def '" - */ -} - -/* - * Pipe stream to or from process. Similar to popen(), only much faster. - * - * This is simpler than popen_noshell() but is more INSECURE. - * Since shells have very complicated expansion, quoting and word splitting algorithms, we do NOT try to re-implement them here. - * This function does NOT support any special characters. It will immediately return an error if such symbols are encountered in "command". - * The "command" is split only by space and tab delimiters. The special symbols are pre-defined in _popen_bash_meta_characters[]. - * The only special characters supported are single and double quotes. You can enclose arguments in quotes and they should be splitted correctly. - * - * If possible, use popen_noshell() because of its better security. - * - * "command" is the command and its arguments to be executed. The command is searched within the PATH environment variable. - * The whole "command" string is parsed and splitted, so that it can be directly given to popen_noshell() and resp. to exec(). - * This parsing is very simple and may contain bugs (see above). If possible, use popen_noshell() directly. - * "type" specifies if we are reading from the STDOUT or writing to the STDIN of the executed command. Use "r" for reading, "w" for writing. - * "pid" is a pointer to an interger. The PID of the child process is stored there. - * - * Returns NULL on any error, "errno" is set appropriately. - * On success, a stream pointer is returned. - * When you are done working with the stream, you have to close it by calling pclose_noshell(), or else you will leave zombie processes. - */ -FILE *popen_noshell_compat(const char *command, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg) { - char **argv; - FILE *fp; - char *to_free; - - argv = popen_noshell_split_command_to_argv(command, &to_free); - if (!argv) { - if (to_free) free(to_free); - return NULL; - } - - fp = popen_noshell(argv[0], (const char * const *)argv, type, pclose_arg, 0); - - free(to_free); - free(argv); - - return fp; -} - -/* - * You have to call this function after you have done working with the FILE pointer "fp" returned by popen_noshell() or by popen_noshell_compat(). - * - * Returns -1 on any error, "errno" is set appropriately. - * Returns the "status" of the child process as returned by waitpid(). - */ -int pclose_noshell(struct popen_noshell_pass_to_pclose *arg) { - int status; - - if (fclose(arg->fp) != 0) { - return -1; - } - - if (waitpid(arg->pid, &status, 0) != arg->pid) { - return -1; - } - - if (arg->free_clone_mem) { - free(arg->stack); - _pclose_noshell_free_clone_arg_memory(arg->func_args); - } - - return status; -} diff --git a/popen-noshell/popen_noshell.h b/popen-noshell/popen_noshell.h deleted file mode 100644 index a2eeb3c6e..000000000 --- a/popen-noshell/popen_noshell.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * popen_noshell: A faster implementation of popen() and system() for Linux. - * Copyright (c) 2009 Ivan Zahariev (famzah) - * Version: 1.0 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef POPEN_NOSHELL_H -#define POPEN_NOSHELL_H - -#include -#include -#include - -/* stack for the child process before it does exec() */ -#define POPEN_NOSHELL_STACK_SIZE 8*1024*1024 /* currently most Linux distros set this to 8 MBytes */ - -/* constants to use with popen_noshell_set_fork_mode() */ -#define POPEN_NOSHELL_MODE_CLONE 0 /* default, faster */ -#define POPEN_NOSHELL_MODE_FORK 1 /* slower */ - -struct popen_noshell_clone_arg { - int pipefd_0; - int pipefd_1; - int read_pipe; - int ignore_stderr; - const char *file; - const char * const *argv; -}; - -struct popen_noshell_pass_to_pclose { - FILE *fp; - pid_t pid; - int free_clone_mem; - void *stack; - struct popen_noshell_clone_arg *func_args; -}; - -/*************************** - * PUBLIC FUNCTIONS FOLLOW * - ***************************/ - -/* this is the native function call */ -FILE *popen_noshell(const char *file, const char * const *argv, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg, int ignore_stderr); - -/* more insecure, but more compatible with popen() */ -FILE *popen_noshell_compat(const char *command, const char *type, struct popen_noshell_pass_to_pclose *pclose_arg); - -/* call this when you have finished reading and writing from/to the child process */ -int pclose_noshell(struct popen_noshell_pass_to_pclose *arg); /* the pclose() equivalent */ - -/* this is the innovative faster vmfork() which shares memory with the parent and is very resource-light; see the source code for documentation */ -pid_t popen_noshell_vmfork(int (*fn)(void *), void *arg, void **memory_to_free_on_child_exit); - -/* used only for benchmarking purposes */ -void popen_noshell_set_fork_mode(int mode); - -#endif From d0573049c94ae0d67415a3ad813013c4fcb18cbf Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 23:33:59 +0200 Subject: [PATCH 10/19] Ignore untracked popen_noshell stuff --- .gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index c806532dd..62312b73f 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,14 @@ kpvcrlib/Makefile popen-noshell/libpopen_noshell.a popen-noshell/*.o +popen-noshell/.svn/ +popen-noshell/CREDITS +popen-noshell/Makefile +popen-noshell/README +popen-noshell/performance_tests/ +popen-noshell/popen_noshell.c +popen-noshell/popen_noshell.h +popen-noshell/popen_noshell_examples.c +popen-noshell/popen_noshell_tests.c +popen-noshell/popen_noshell_tests.cpp + From 76714c453afaa368e038e5ecf6f44760b13dff59 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 2 Oct 2012 23:50:34 +0200 Subject: [PATCH 11/19] Restore Makefiles tweaks --- Makefile | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7a6ce5722..40442bab9 100644 --- a/Makefile +++ b/Makefile @@ -30,10 +30,13 @@ endif HOSTCC:=gcc HOSTCXX:=g++ -CFLAGS:=-O3 $(SYSROOT) -CXXFLAGS:=-O3 $(SYSROOT) +# Base CFLAGS, without arch. Will use it as-is for luajit, because its buildsystem picks up the wrong flags, possibly from my env... +BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer -fno-stack-protector -U_FORTIFY_SOURCE +CFLAGS:=$(BASE_CFLAGS) +CXXFLAGS:=$(BASE_CFLAGS) -fno-use-cxa-atexit LDFLAGS:=-Wl,-O1 -Wl,--as-needed ARM_CFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp +HOSTCFLAGS:=-O2 -march=native -ffast-math -pipe -fomit-frame-pointer # use this for debugging: #CFLAGS:=-O0 -g @@ -172,7 +175,7 @@ clean: rm -f *.o kpdfview slider_watcher cleanthirdparty: - $(MAKE) -C $(LUADIR) clean + $(MAKE) -C $(LUADIR) clean CFLAGS="" $(MAKE) -C $(MUPDFDIR) build="release" clean $(MAKE) -C $(CRENGINEDIR)/thirdparty/antiword clean test -d $(CRENGINEDIR)/thirdparty/chmlib && $(MAKE) -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found @@ -185,12 +188,12 @@ cleanthirdparty: $(MAKE) -C $(POPENNSDIR) clean $(MUPDFDIR)/fontdump.host: - $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/fontdump + $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/fontdump cp -a $(MUPDFLIBDIR)/fontdump $(MUPDFDIR)/fontdump.host $(MAKE) -C mupdf clean $(MUPDFDIR)/cmapdump.host: - $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" $(MUPDFTARGET)/cmapdump + $(MAKE) -C mupdf build="release" CC="$(HOSTCC)" CFLAGS="$(HOSTCFLAGS) -I../mupdf/fitz -I../mupdf/pdf" $(MUPDFTARGET)/cmapdump cp -a $(MUPDFLIBDIR)/cmapdump $(MUPDFDIR)/cmapdump.host $(MAKE) -C mupdf clean @@ -216,7 +219,7 @@ $(LUALIB): ifdef EMULATE_READER $(MAKE) -C $(LUADIR) else - $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(CHOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" + $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(BASE_CFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(CHOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" endif $(POPENNSLIB): From 9cc106995d15252267762cf13a38d51d523167a2 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 00:29:10 +0200 Subject: [PATCH 12/19] Properly fix the luajit *FLAGS mess --- Makefile | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index fa034ec45..8923ab1db 100644 --- a/Makefile +++ b/Makefile @@ -30,15 +30,16 @@ endif HOSTCC:=gcc HOSTCXX:=g++ -# Base CFLAGS, without arch. Will use it as-is for luajit, because its buildsystem picks up the wrong flags, possibly from my env... +# Base CFLAGS, without arch. We'll need it for luajit, because its Makefiles do some tricky stuff to differentiate HOST/TARGET BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer -fno-stack-protector -U_FORTIFY_SOURCE +# Use this for debugging: +#BASE_CFLAGS:=-O0 -g +ARM_ARCH:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp +HOST_ARCH:=-march=native +HOSTCFLAGS:=$(HOST_CFLAGS) $(BASE_CFLAGS) CFLAGS:=$(BASE_CFLAGS) CXXFLAGS:=$(BASE_CFLAGS) -fno-use-cxa-atexit LDFLAGS:=-Wl,-O1 -Wl,--as-needed -ARM_CFLAGS:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp -HOSTCFLAGS:=-O2 -march=native -ffast-math -pipe -fomit-frame-pointer -# use this for debugging: -#CFLAGS:=-O0 -g DYNAMICLIBSTDCPP:=-lstdc++ ifdef STATICLIBSTDCPP @@ -62,9 +63,11 @@ ifdef EMULATE_READER ifeq "$(shell uname -s -m)" "Darwin x86_64" EMU_LDFLAGS += -pagezero_size 10000 -image_base 100000000 endif + CFLAGS+= $(HOST_ARCH) + CXXFLAGS+= $(HOST_ARCH) else - CFLAGS+= $(ARM_CFLAGS) - CXXFLAGS+= $(ARM_CFLAGS) + CFLAGS+= $(ARM_ARCH) + CXXFLAGS+= $(ARM_ARCH) endif # standard includes @@ -175,7 +178,7 @@ clean: rm -f *.o kpdfview slider_watcher cleanthirdparty: - $(MAKE) -C $(LUADIR) clean CFLAGS="" + $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(CHOST)-" clean $(MAKE) -C $(MUPDFDIR) build="release" clean $(MAKE) -C $(CRENGINEDIR)/thirdparty/antiword clean test -d $(CRENGINEDIR)/thirdparty/chmlib && $(MAKE) -C $(CRENGINEDIR)/thirdparty/chmlib clean || echo warn: chmlib folder not found @@ -219,7 +222,8 @@ $(LUALIB): ifdef EMULATE_READER $(MAKE) -C $(LUADIR) else - $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(BASE_CFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(CHOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" + # To recap: build its TARGET_CC from CROSS+CC, so we need HOSTCC in CC. Build its HOST/TARGET_CFLAGS based on CFLAGS, so we need a neutral CFLAGS without arch + $(MAKE) -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CFLAGS="$(BASE_CFLAGS)" HOST_CFLAGS="$(HOSTCFLAGS)" TARGET_CFLAGS="$(CFLAGS)" CROSS="$(CHOST)-" TARGET_FLAGS="-DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" endif $(POPENNSLIB): From 4356622186e158a21e0af9d853ef47cf9ff3625d Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 00:34:42 +0200 Subject: [PATCH 13/19] Don't patch popen-noshell twice --- Makefile | 2 +- popen-noshell/popen_noshell-buildfix.patch | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8923ab1db..5f98a1205 100644 --- a/Makefile +++ b/Makefile @@ -172,7 +172,7 @@ fetchthirdparty: cd mupdf && patch -N -p1 < ../mupdf.patch svn co http://popen-noshell.googlecode.com/svn/trunk/ popen-noshell # popen_noshell patch: Make it build on recent TCs, and implement a simple Makefile for building it as a static lib - cd popen-noshell && patch -N -p0 < popen_noshell-buildfix.patch + cd popen-noshell && tesf -f Makefile || patch -N -p0 < popen_noshell-buildfix.patch clean: rm -f *.o kpdfview slider_watcher diff --git a/popen-noshell/popen_noshell-buildfix.patch b/popen-noshell/popen_noshell-buildfix.patch index 6f9ba1bf8..97c09b881 100644 --- a/popen-noshell/popen_noshell-buildfix.patch +++ b/popen-noshell/popen_noshell-buildfix.patch @@ -15,7 +15,7 @@ Index: Makefile =================================================================== --- Makefile (revision 0) +++ Makefile (working copy) -@@ -0,0 +1,15 @@ +@@ -0,0 +1,17 @@ +SRCS=popen_noshell.c + +OBJS:=$(SRCS:%.c=%.o) @@ -31,6 +31,8 @@ Index: Makefile +clean: + rm -rf *.o + rm -rf libpopen_noshell.a ++ ++.PHONY: clean Property changes on: Makefile ___________________________________________________________________ From 7bc80277e4711cdaa55c52df563aae38296d9cf9 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 00:36:50 +0200 Subject: [PATCH 14/19] Don't checkout popen_noshell twice (it reverts parts of our patch) --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5f98a1205..a82a81871 100644 --- a/Makefile +++ b/Makefile @@ -170,9 +170,9 @@ fetchthirdparty: patch -N -p0 < ../../../kpvcrlib/jpeg_decompress_struct_size.patch # MuPDF patch: use external fonts cd mupdf && patch -N -p1 < ../mupdf.patch - svn co http://popen-noshell.googlecode.com/svn/trunk/ popen-noshell + test -f popen-noshell/popen_noshell.c || svn co http://popen-noshell.googlecode.com/svn/trunk/ popen-noshell # popen_noshell patch: Make it build on recent TCs, and implement a simple Makefile for building it as a static lib - cd popen-noshell && tesf -f Makefile || patch -N -p0 < popen_noshell-buildfix.patch + cd popen-noshell && test -f Makefile || patch -N -p0 < popen_noshell-buildfix.patch clean: rm -f *.o kpdfview slider_watcher From 8b45833e2d5acdd7425d937590baf8735cc7d7ac Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 01:17:21 +0200 Subject: [PATCH 15/19] Kill a bit of cruft, explain the reasonning behind the kill/traps, and fix a potential buffering issue eating the first slider event --- input.c | 29 +++++++++++++---------------- kpdfview.c | 9 --------- slider_watcher.c | 11 ++--------- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/input.c b/input.c index 126f94a9c..7f79d1986 100644 --- a/input.c +++ b/input.c @@ -50,7 +50,8 @@ void slider_handler(int sig) { /* Kill lipc-wait-event properly on exit */ if(pclose_arg.pid != 0) { - kill(pclose_arg.pid, SIGTERM); + // Be a little more gracious, lipc seems to handle SIGINT properly + kill(pclose_arg.pid, SIGINT); } } @@ -84,7 +85,7 @@ static int openInputDevice(lua_State *L) { return luaL_error(L, "cannot fork() slider event listener"); } if(childpid == 0) { - // Setup signal handler, to cleanup on exit + // We send a SIGTERM to this child on exit, trap it to kill lipc properly. signal(SIGTERM, slider_handler); FILE *fp; @@ -99,25 +100,21 @@ static int openInputDevice(lua_State *L) { ev.code = key_code; ev.value = 1; - /* listen power slider events */ - char *exec_file = "lipc-wait-event"; - char *arg1 = "-m"; // Hang for ever, don't exit on the first one: we're in a dedicated child, and we'll be killed/closed on exit, so we don't care - char *arg2 = "-s"; - char *arg3 = "0"; - char *arg4 = "com.lab126.powerd"; - char *arg5 = "goingToScreenSaver,outOfScreenSaver,charging,notCharging"; - char *arg6 = (char *) NULL; - char *argv[] = {exec_file, arg1, arg2, arg3, arg4, arg5, arg6}; + /* listen power slider events (listen for ever for multiple events) */ + char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver,charging,notCharging", (char *) NULL}; /* @TODO 07.06 2012 (houqp) * plugin and out event can only be watched by: lipc-wait-event com.lab126.hal usbPlugOut,usbPlugIn */ - fp = popen_noshell(exec_file, (const char * const *)argv, "r", &pclose_arg, 0); + fp = popen_noshell("lipc-wait-event", (const char * const *)argv, "r", &pclose_arg, 0); if (!fp) { err(EXIT_FAILURE, "popen_noshell()"); } + /* Flush to get rid of buffering issues? */ + fflush(fp); + while(fgets(std_out, sizeof(std_out)-1, fp)) { if(std_out[0] == 'g') { ev.code = CODE_IN_SAVER; @@ -147,13 +144,13 @@ static int openInputDevice(lua_State *L) { if (status == -1) { err(EXIT_FAILURE, "pclose_noshell()"); } else { - printf("Power slider event listener child exited with status %d.\n", status); + printf("lipc-wait-event exited with status %d.\n", status); if WIFEXITED(status) { - printf("Child exited normally with status: %d.\n", WEXITSTATUS(status)); + printf("lipc-wait-event exited normally with status: %d.\n", WEXITSTATUS(status)); } if WIFSIGNALED(status) { - printf("Child terminated by signal: %d.\n", WTERMSIG(status)); + printf("lipc-wait-event terminated by signal: %d.\n", WTERMSIG(status)); } } @@ -193,7 +190,7 @@ static int closeInputDevices(lua_State *L) { } if(slider_pid != -1) { /* kill and wait for child process */ - kill(slider_pid, SIGTERM); + kill(slider_pid, SIGTERM); // We could kill -slider_pid (note the minus) to kill the whole process group, but we trap SIGTERM to handle things nicely waitpid(-1, NULL, 0); } return 0; diff --git a/kpdfview.c b/kpdfview.c index 08ec30283..15858df33 100644 --- a/kpdfview.c +++ b/kpdfview.c @@ -83,15 +83,6 @@ int main(int argc, char **argv) { } } - /* Make popen_noshell & valgrind happy */ - if (fflush(stdout) != 0) - err(EXIT_FAILURE, "fflush(stdout)"); - if (fflush(stderr) != 0) - err(EXIT_FAILURE, "fflush(stderr)"); - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - return 0; } diff --git a/slider_watcher.c b/slider_watcher.c index cca6827a5..3d16c06ad 100644 --- a/slider_watcher.c +++ b/slider_watcher.c @@ -65,16 +65,9 @@ main ( int argc, char *argv[] ) ev.value = 1; /* listen power slider events */ - char *exec_file = "lipc-wait-event"; - char *arg1 = "-m"; - char *arg2 = "-s"; - char *arg3 = "0"; - char *arg4 = "com.lab126.powerd"; - char *arg5 = "goingToScreenSaver,outOfScreenSaver"; - char *arg6 = (char *) NULL; - char *chargv[] = {exec_file, arg1, arg2, arg3, arg4, arg5, arg6}; + char *argv[] = {"lipc-wait-event", "-m", "-s", "0", "com.lab126.powerd", "goingToScreenSaver,outOfScreenSaver", (char *) NULL}; - fp = popen_noshell(exec_file, (const char * const *)chargv, "r", &pclose_arg, 0); + fp = popen_noshell("lipc-wait-event", (const char * const *)chargv, "r", &pclose_arg, 0); if (!fp) { err(EXIT_FAILURE, "popen_noshell()"); } From 3c181ead772fff5973f3259a49744a1d4525d945 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 01:23:34 +0200 Subject: [PATCH 16/19] Actually, no that's wrong, it's not the parent process, it's a fork. --- input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.c b/input.c index 7f79d1986..d781c5b10 100644 --- a/input.c +++ b/input.c @@ -190,7 +190,7 @@ static int closeInputDevices(lua_State *L) { } if(slider_pid != -1) { /* kill and wait for child process */ - kill(slider_pid, SIGTERM); // We could kill -slider_pid (note the minus) to kill the whole process group, but we trap SIGTERM to handle things nicely + kill(slider_pid, SIGTERM); waitpid(-1, NULL, 0); } return 0; From a2ce5dd101eeaff97cfe4f3f0843175fdad8deaa Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 01:37:20 +0200 Subject: [PATCH 17/19] Hello, tiny stupid typo! --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a82a81871..5480ae96e 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ BASE_CFLAGS:=-O2 -ffast-math -pipe -fomit-frame-pointer -fno-stack-protector -U_ #BASE_CFLAGS:=-O0 -g ARM_ARCH:=-march=armv6j -mtune=arm1136jf-s -mfpu=vfp HOST_ARCH:=-march=native -HOSTCFLAGS:=$(HOST_CFLAGS) $(BASE_CFLAGS) +HOSTCFLAGS:=$(HOST_ARCH) $(BASE_CFLAGS) CFLAGS:=$(BASE_CFLAGS) CXXFLAGS:=$(BASE_CFLAGS) -fno-use-cxa-atexit LDFLAGS:=-Wl,-O1 -Wl,--as-needed From 9acdedcaebed81bf4ac239213ea56ed9e7a5b85d Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 01:41:32 +0200 Subject: [PATCH 18/19] Forgot to revert that too, useless now :). --- kpdfview.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kpdfview.c b/kpdfview.c index 15858df33..0f8a674f2 100644 --- a/kpdfview.c +++ b/kpdfview.c @@ -15,13 +15,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include -#include -#include -#include #include #include -#include +#include #include #include From c7fa11e7e9f29e7ac8e0c180f4b7a624deeee383 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 3 Oct 2012 01:46:56 +0200 Subject: [PATCH 19/19] Slight syntax tweak --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5480ae96e..17a987b01 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,7 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o $(POPENNS $(CRENGINELIBS) \ $(STATICLIBSTDCPP) \ $(LDFLAGS) \ - -o kpdfview -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP) + -o $@ -lm -ldl -lpthread $(EMU_LDFLAGS) $(DYNAMICLIBSTDCPP) slider_watcher.o: %.o: %.c $(CC) -c $(CFLAGS) $< -o $@