From 4365fbe2a373b73af5578d0ed6eddfb2ba9901ef Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Wed, 28 May 2008 15:28:13 +0000 Subject: [PATCH] Squashed commit of the following: commit d45d1757d24d8214f730af1a3401dd2bef4a434f Author: Steven Date: Wed May 28 17:23:27 2008 +0200 * libs/core: Removed dummymode checks in sys * libs/sgi-webuci: Fixes commit b870e8d345bc8912fd8ab61d463b9d68b924a6f4 Author: Felix Fietkau Date: Wed May 28 15:40:10 2008 +0200 fix path to theme commit e3732926bd98db4cc38de6eb8018cd4e55176699 Author: Felix Fietkau Date: Wed May 28 14:56:03 2008 +0200 set the proper path to the config in dummy mode commit a75aecf46f037c98bd6e49b9e48adb735d76d150 Author: Felix Fietkau Date: Wed May 28 14:50:42 2008 +0200 add some dummy mode support commit 12bb39ef606bca6b403cc982213a6597b76dc1b3 Author: Felix Fietkau Date: Wed May 28 14:41:56 2008 +0200 normalize paths commit 7aaad1103fd2bdc75aca158baa6ef191f9a961c6 Author: Felix Fietkau Date: Wed May 28 14:27:26 2008 +0200 add missing require statement commit 5766274bd2511b00c42b474aeeeb3efaca6ded9b Author: Felix Fietkau Date: Wed May 28 14:19:54 2008 +0200 add optional luaposix package (patched for darwin support) commit 9e257a76d03722fc0ce8312aa9952641b21424bd Author: Felix Fietkau Date: Tue May 27 20:21:59 2008 +0200 add missing files, more integration for the boa plugin, fix path to lua modules commit dacc1a98ec946975fcb19f87076dfa7db865fca6 Author: Felix Fietkau Date: Tue May 27 19:42:37 2008 +0200 use "compile" instead of "source" and rename the old version of compile to "compile-all" commit eb14777c4fee1eb5740aba1e5603e481320da7b1 Author: Felix Fietkau Date: Tue May 27 19:41:59 2008 +0200 more boa integration commit df0afb965bf0a987b653e9d0acadf3151179a596 Author: Felix Fietkau Date: Tue May 27 18:33:42 2008 +0200 build boa and the webuci.so plugin along with sgi-webuci commit 878161dabf32066631103d199e2cbaf3f5a7fb07 Author: Felix Fietkau Date: Tue May 27 18:03:16 2008 +0200 add .gitignore --- .gitignore | 2 + Makefile | 8 +- build/config.mk | 27 +- build/module.mk | 3 +- contrib/luaposix/.gitignore | 2 + contrib/luaposix/Makefile | 43 + contrib/luaposix/patches/100-darwin_compile.patch | 27 + libs/core/luasrc/sys.lua | 2 +- libs/sgi-webuci/.gitignore | 4 + libs/sgi-webuci/Makefile | 51 +- libs/sgi-webuci/boa-patches/100-no_tz.patch | 22 + libs/sgi-webuci/boa-patches/200-plugin_api.patch | 1089 ++++++++++++++++++++ libs/sgi-webuci/luasrc/sgi/webuci.lua | 5 +- libs/sgi-webuci/root/etc/boa/boa.conf | 16 + libs/sgi-webuci/root/etc/mime.types | 748 ++++++++++++++ libs/sgi-webuci/root/lib/webuci/main.lua | 20 - libs/sgi-webuci/root/usr/lib/boa/luci.lua | 61 ++ libs/sgi-webuci/src/cgi.c | 530 ++++++++++ libs/sgi-webuci/src/luci.c | 216 ++++ libs/web/root/etc/config/luci | 6 +- .../{luci => luci-static}/fledermaus/cascade.css | 0 .../www/{luci => luci-static}/fledermaus/logo.png | Bin 22 files changed, 2851 insertions(+), 31 deletions(-) create mode 100644 .gitignore create mode 100644 contrib/luaposix/.gitignore create mode 100644 contrib/luaposix/Makefile create mode 100644 contrib/luaposix/patches/100-darwin_compile.patch create mode 100644 libs/sgi-webuci/.gitignore create mode 100644 libs/sgi-webuci/boa-patches/100-no_tz.patch create mode 100644 libs/sgi-webuci/boa-patches/200-plugin_api.patch create mode 100644 libs/sgi-webuci/root/etc/boa/boa.conf create mode 100644 libs/sgi-webuci/root/etc/mime.types delete mode 100644 libs/sgi-webuci/root/lib/webuci/main.lua create mode 100644 libs/sgi-webuci/root/usr/lib/boa/luci.lua create mode 100644 libs/sgi-webuci/src/cgi.c create mode 100644 libs/sgi-webuci/src/luci.c rename themes/fledermaus/root/www/{luci => luci-static}/fledermaus/cascade.css (100%) rename themes/fledermaus/root/www/{luci => luci-static}/fledermaus/logo.png (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..bf9420cee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist/ +/host diff --git a/Makefile b/Makefile index 4b3fb64f4..d76be9a2d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ include build/config.mk MODULES = applications/* libs/* modules/* themes/* i18n/* -LUA_TARGET = source - +LUA_TARGET = compile +OS:=$(shell uname) +export OS +ifeq ($(OS),Darwin) + MODULES += contrib/luaposix +endif .PHONY: all build clean host hostclean diff --git a/build/config.mk b/build/config.mk index 66585289b..9db99cd6b 100644 --- a/build/config.mk +++ b/build/config.mk @@ -1,3 +1,28 @@ +OS ?= $(shell uname) + LUAC = luac LUAC_OPTIONS = -s -LUCI_INSTALLDIR = /usr/lib/lua/luci \ No newline at end of file +LUCI_INSTALLDIR = /usr/lib/lua/luci +LUA_SHLIBS = $(shell pkg-config --silence-errors --libs lua5.1) +LUA_LIBS = $(if $(LUA_SHLIBS),$(LUA_SHLIBS),$(firstword $(wildcard /usr/lib/liblua.a /usr/local/lib/liblua.a /opt/local/lib/liblua.a))) +LUA_CFLAGS = $(shell pkg-config --silence-errors --cflags lua5.1) +ifeq ($(LUA_LIBS),) + $(error LUA installation not found) +endif + +CC = gcc +AR = ar +RANLIB = ranlib +CFLAGS = -O2 +FPIC = -fPIC +EXTRA_CFLAGS = --std=gnu99 +WFLAGS = -Wall -Werror -pedantic +CPPFLAGS = +COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $(WFLAGS) +ifeq ($(OS),Darwin) + SHLIB_FLAGS = -bundle -undefined dynamic_lookup +else + SHLIB_FLAGS = -shared +endif +LINK = $(CC) + diff --git a/build/module.mk b/build/module.mk index 287314696..923caad70 100644 --- a/build/module.mk +++ b/build/module.mk @@ -1,7 +1,8 @@ .PHONY: all compile compile-module source source-module clean clean-module all: compile -compile: compile-module +compile: source-module +compile-all: compile-module clean: clean-module source: source-module diff --git a/contrib/luaposix/.gitignore b/contrib/luaposix/.gitignore new file mode 100644 index 000000000..c900421f8 --- /dev/null +++ b/contrib/luaposix/.gitignore @@ -0,0 +1,2 @@ +luaposix-* +patches/series diff --git a/contrib/luaposix/Makefile b/contrib/luaposix/Makefile new file mode 100644 index 000000000..4f16b5362 --- /dev/null +++ b/contrib/luaposix/Makefile @@ -0,0 +1,43 @@ +include ../../build/config.mk + +LUAPOSIX_VERSION = 5.1.2 +LUAPOSIX_SITE = http://luaforge.net/frs/download.php/3063/ +LUAPOSIX_DIR = luaposix-$(LUAPOSIX_VERSION) +LUAPOSIX_FILE = $(LUAPOSIX_DIR).tar.gz +LUAPOSIX_URL = $(LUAPOSIX_SITE)/$(LUAPOSIX_FILE) +LUAPOSIX_PATCHDIR = patches + +all: compile + +$(LUAPOSIX_FILE): + wget -O $@ $(LUAPOSIX_URL) || rm -f $@ + +$(LUAPOSIX_PATCHDIR)/series: + (cd $(LUAPOSIX_PATCHDIR); ls *.patch | sort > series) + +$(LUAPOSIX_DIR)/.prepared: $(LUAPOSIX_FILE) + rm -rf $(LUAPOSIX_DIR) + tar xvfz $(LUAPOSIX_FILE) + ln -s ../$(LUAPOSIX_PATCHDIR) $(LUAPOSIX_DIR)/patches + touch $@ + +$(LUAPOSIX_DIR)/.patched: $(LUAPOSIX_DIR)/.prepared $(LUAPOSIX_PATCHDIR)/series + (cd $(LUAPOSIX_DIR); \ + if [ -x "$$(which quilt 2>/dev/null)" ]; then \ + quilt push -a; \ + else \ + cat patches/*.patch | patch -p1; \ + fi; \ + ) + touch $@ + +compile: $(LUAPOSIX_DIR)/.patched + $(MAKE) -C $(LUAPOSIX_DIR) CC=$(CC) CFLAGS="$(CFLAGS)" OS="$(OS)" + mkdir -p dist/usr/lib/lua + cp $(LUAPOSIX_DIR)/posix.so dist/usr/lib/lua/ + +compile-all: compile + +clean: + rm -rf $(LUAPOSIX_DIR) $(LUAPOSIX_FILE) + rm -f $(LUAPOSIX_PATCHDIR)/series diff --git a/contrib/luaposix/patches/100-darwin_compile.patch b/contrib/luaposix/patches/100-darwin_compile.patch new file mode 100644 index 000000000..07943acab --- /dev/null +++ b/contrib/luaposix/patches/100-darwin_compile.patch @@ -0,0 +1,27 @@ +Index: luaposix-5.1.2/Makefile +=================================================================== +--- luaposix-5.1.2.orig/Makefile 2008-01-29 14:49:27.000000000 +0100 ++++ luaposix-5.1.2/Makefile 2008-05-28 14:15:30.000000000 +0200 +@@ -34,6 +34,13 @@ + + T= $(MYLIB).so + ++OS=$(shell uname) ++ifeq ($(OS),Darwin) ++ LDFLAGS_SHARED=-bundle -undefined dynamic_lookup ++else ++ LDFLAGS_SHARED=-shared ++endif ++ + # targets + phony += all + all: $T +@@ -43,7 +50,7 @@ + $(LUA) test.lua + + $T: $(OBJS) +- $(CC) $(LDFLAGS) -o $@ -shared $(OBJS) ++ $(CC) $(LDFLAGS) -o $@ $(LDFLAGS_SHARED) $(OBJS) + + $(OBJS): modemuncher.c + diff --git a/libs/core/luasrc/sys.lua b/libs/core/luasrc/sys.lua index 0399d0e5f..6d03f59db 100644 --- a/libs/core/luasrc/sys.lua +++ b/libs/core/luasrc/sys.lua @@ -368,4 +368,4 @@ function _parse_mixed_record(cnt) end return data -end \ No newline at end of file +end diff --git a/libs/sgi-webuci/.gitignore b/libs/sgi-webuci/.gitignore new file mode 100644 index 000000000..e6f1e58a8 --- /dev/null +++ b/libs/sgi-webuci/.gitignore @@ -0,0 +1,4 @@ +boa-patches/series +boa-*.* +*.o +*.so diff --git a/libs/sgi-webuci/Makefile b/libs/sgi-webuci/Makefile index 81a96f6a8..9efe0fe14 100644 --- a/libs/sgi-webuci/Makefile +++ b/libs/sgi-webuci/Makefile @@ -1,2 +1,51 @@ include ../../build/config.mk -include ../../build/module.mk \ No newline at end of file +include ../../build/module.mk + +BOA_VERSION = 0.94.13 +BOA_SITE = http://www.boa.org +BOA_DIR = boa-$(BOA_VERSION) +BOA_FILE = $(BOA_DIR).tar.gz +BOA_URL = $(BOA_SITE)/$(BOA_FILE) +BOA_PATCHDIR = boa-patches + +$(BOA_FILE): + wget -O $@ $(BOA_URL) || rm -f $@ + +$(BOA_PATCHDIR)/series: + (cd $(BOA_PATCHDIR); ls *.patch | sort > series) + +$(BOA_DIR)/.prepared: $(BOA_FILE) + rm -rf $(BOA_DIR) + tar xvfz $(BOA_FILE) + ln -s ../$(BOA_PATCHDIR) $(BOA_DIR)/patches + touch $@ + +$(BOA_DIR)/.patched: $(BOA_DIR)/.prepared $(BOA_PATCHDIR)/series + (cd $(BOA_DIR); \ + if [ -x "$$(which quilt 2>/dev/null)" ]; then \ + quilt push -a; \ + else \ + cat patches/*.patch | patch -p1; \ + fi; \ + ) + touch $@ + +$(BOA_DIR)/.configured: $(BOA_DIR)/.patched + (cd $(BOA_DIR)/src; ./configure --disable-debug) + touch $@ + +boa-compile: $(BOA_DIR)/.configured + $(MAKE) -C $(BOA_DIR)/src CC=$(CC) CFLAGS="$(CFLAGS)" + +%.o: %.c + $(COMPILE) $(LUA_CFLAGS) -I$(BOA_DIR)/src $(FPIC) -c -o $@ $< + +compile: boa-compile src/luci.o src/cgi.o + mkdir -p dist/usr/bin dist/usr/lib/boa + cp $(BOA_DIR)/src/boa $(BOA_DIR)/src/boa_indexer dist/usr/bin + $(LINK) $(SHLIB_FLAGS) $(LUA_SHLIBS) -o dist/usr/lib/boa/luci.so src/luci.o src/cgi.o $(LUA_LIBS) + +clean: + rm -rf $(BOA_DIR) $(BOA_FILE) + rm -f boa-patches/series + rm -f src/*.o diff --git a/libs/sgi-webuci/boa-patches/100-no_tz.patch b/libs/sgi-webuci/boa-patches/100-no_tz.patch new file mode 100644 index 000000000..639677eed --- /dev/null +++ b/libs/sgi-webuci/boa-patches/100-no_tz.patch @@ -0,0 +1,22 @@ +diff -urN boa-0.94.13/src/util.c boa/src/util.c +--- boa-0.94.13/src/util.c 2002-07-08 01:22:18.000000000 +0200 ++++ boa/src/util.c 2008-04-25 21:56:20.000000000 +0200 +@@ -95,14 +95,9 @@ + static char buf[30]; + int time_offset; + +- if (use_localtime) { +- t = localtime(¤t_time); +- time_offset = TIMEZONE_OFFSET(t); +- } else { +- t = gmtime(¤t_time); +- time_offset = 0; +- } +- ++ t = gmtime(¤t_time); ++ time_offset = 0; ++ + p = buf + 29; + *p-- = '\0'; + *p-- = ' '; + diff --git a/libs/sgi-webuci/boa-patches/200-plugin_api.patch b/libs/sgi-webuci/boa-patches/200-plugin_api.patch new file mode 100644 index 000000000..de7999159 --- /dev/null +++ b/libs/sgi-webuci/boa-patches/200-plugin_api.patch @@ -0,0 +1,1089 @@ +Index: boa-0.94.13/src/list.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ boa-0.94.13/src/list.h 2008-05-27 19:28:21.000000000 +0200 +@@ -0,0 +1,601 @@ ++#ifndef _LINUX_LIST_H ++#define _LINUX_LIST_H ++ ++#include ++/** ++ * container_of - cast a member of a structure out to the containing structure ++ * @ptr: the pointer to the member. ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ * ++ */ ++#ifndef container_of ++#define container_of(ptr, type, member) ( \ ++ (type *)( (char *)ptr - offsetof(type,member) )) ++#endif ++ ++ ++/* ++ * Simple doubly linked list implementation. ++ * ++ * Some of the internal functions ("__xxx") are useful when ++ * manipulating whole lists rather than single entries, as ++ * sometimes we already know the next/prev entries and we can ++ * generate better code by using them directly rather than ++ * using the generic single-entry routines. ++ */ ++ ++struct list_head { ++ struct list_head *next, *prev; ++}; ++ ++#define LIST_HEAD_INIT(name) { &(name), &(name) } ++ ++#define LIST_HEAD(name) \ ++ struct list_head name = LIST_HEAD_INIT(name) ++ ++static inline void INIT_LIST_HEAD(struct list_head *list) ++{ ++ list->next = list; ++ list->prev = list; ++} ++ ++/* ++ * Insert a new entry between two known consecutive entries. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_add(struct list_head *new, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ next->prev = new; ++ new->next = next; ++ new->prev = prev; ++ prev->next = new; ++} ++ ++/** ++ * list_add - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it after ++ * ++ * Insert a new entry after the specified head. ++ * This is good for implementing stacks. ++ */ ++static inline void list_add(struct list_head *new, struct list_head *head) ++{ ++ __list_add(new, head, head->next); ++} ++ ++ ++/** ++ * list_add_tail - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it before ++ * ++ * Insert a new entry before the specified head. ++ * This is useful for implementing queues. ++ */ ++static inline void list_add_tail(struct list_head *new, struct list_head *head) ++{ ++ __list_add(new, head->prev, head); ++} ++ ++ ++/* ++ * Delete a list entry by making the prev/next entries ++ * point to each other. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_del(struct list_head * prev, struct list_head * next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++ ++/** ++ * list_del - deletes entry from list. ++ * @entry: the element to delete from the list. ++ * Note: list_empty() on entry does not return true after this, the entry is ++ * in an undefined state. ++ */ ++static inline void list_del(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ entry->next = NULL; ++ entry->prev = NULL; ++} ++ ++/** ++ * list_replace - replace old entry by new one ++ * @old : the element to be replaced ++ * @new : the new element to insert ++ * ++ * If @old was empty, it will be overwritten. ++ */ ++static inline void list_replace(struct list_head *old, ++ struct list_head *new) ++{ ++ new->next = old->next; ++ new->next->prev = new; ++ new->prev = old->prev; ++ new->prev->next = new; ++} ++ ++static inline void list_replace_init(struct list_head *old, ++ struct list_head *new) ++{ ++ list_replace(old, new); ++ INIT_LIST_HEAD(old); ++} ++ ++/** ++ * list_del_init - deletes entry from list and reinitialize it. ++ * @entry: the element to delete from the list. ++ */ ++static inline void list_del_init(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ INIT_LIST_HEAD(entry); ++} ++ ++/** ++ * list_move - delete from one list and add as another's head ++ * @list: the entry to move ++ * @head: the head that will precede our entry ++ */ ++static inline void list_move(struct list_head *list, struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add(list, head); ++} ++ ++/** ++ * list_move_tail - delete from one list and add as another's tail ++ * @list: the entry to move ++ * @head: the head that will follow our entry ++ */ ++static inline void list_move_tail(struct list_head *list, ++ struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add_tail(list, head); ++} ++ ++/** ++ * list_is_last - tests whether @list is the last entry in list @head ++ * @list: the entry to test ++ * @head: the head of the list ++ */ ++static inline int list_is_last(const struct list_head *list, ++ const struct list_head *head) ++{ ++ return list->next == head; ++} ++ ++/** ++ * list_empty - tests whether a list is empty ++ * @head: the list to test. ++ */ ++static inline int list_empty(const struct list_head *head) ++{ ++ return head->next == head; ++} ++ ++/** ++ * list_empty_careful - tests whether a list is empty and not being modified ++ * @head: the list to test ++ * ++ * Description: ++ * tests whether a list is empty _and_ checks that no other CPU might be ++ * in the process of modifying either member (next or prev) ++ * ++ * NOTE: using list_empty_careful() without synchronization ++ * can only be safe if the only activity that can happen ++ * to the list entry is list_del_init(). Eg. it cannot be used ++ * if another CPU could re-list_add() it. ++ */ ++static inline int list_empty_careful(const struct list_head *head) ++{ ++ struct list_head *next = head->next; ++ return (next == head) && (next == head->prev); ++} ++ ++static inline void __list_splice(struct list_head *list, ++ struct list_head *head) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ struct list_head *at = head->next; ++ ++ first->prev = head; ++ head->next = first; ++ ++ last->next = at; ++ at->prev = last; ++} ++ ++/** ++ * list_splice - join two lists ++ * @list: the new list to add. ++ * @head: the place to add it in the first list. ++ */ ++static inline void list_splice(struct list_head *list, struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice(list, head); ++} ++ ++/** ++ * list_splice_init - join two lists and reinitialise the emptied list. ++ * @list: the new list to add. ++ * @head: the place to add it in the first list. ++ * ++ * The list at @list is reinitialised ++ */ ++static inline void list_splice_init(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) { ++ __list_splice(list, head); ++ INIT_LIST_HEAD(list); ++ } ++} ++ ++/** ++ * list_entry - get the struct for this entry ++ * @ptr: the &struct list_head pointer. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_entry(ptr, type, member) \ ++ container_of(ptr, type, member) ++ ++/** ++ * list_first_entry - get the first element from a list ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Note, that list is expected to be not empty. ++ */ ++#define list_first_entry(ptr, type, member) \ ++ list_entry((ptr)->next, type, member) ++ ++/** ++ * list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ */ ++#define list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); \ ++ pos = pos->next) ++ ++/** ++ * __list_for_each - iterate over a list ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ * ++ * This variant differs from list_for_each() in that it's the ++ * simplest possible list iteration code, no prefetching is done. ++ * Use this for code that knows the list to be very short (empty ++ * or 1 entry) most of the time. ++ */ ++#define __list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++ ++/** ++ * list_for_each_prev - iterate over a list backwards ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ */ ++#define list_for_each_prev(pos, head) \ ++ for (pos = (head)->prev; pos != (head); \ ++ pos = pos->prev) ++ ++/** ++ * list_for_each_safe - iterate over a list safe against removal of list entry ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. ++ */ ++#define list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++ ++/** ++ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @n: another &struct list_head to use as temporary storage ++ * @head: the head for your list. ++ */ ++#define list_for_each_prev_safe(pos, n, head) \ ++ for (pos = (head)->prev, n = pos->prev; \ ++ pos != (head); \ ++ pos = n, n = pos->prev) ++ ++/** ++ * list_for_each_entry - iterate over list of given type ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_reverse - iterate backwards over list of given type. ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_reverse(pos, head, member) \ ++ for (pos = list_entry((head)->prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.prev, typeof(*pos), member)) ++ ++/** ++ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() ++ * @pos: the type * to use as a start point ++ * @head: the head of the list ++ * @member: the name of the list_struct within the struct. ++ * ++ * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). ++ */ ++#define list_prepare_entry(pos, head, member) \ ++ ((pos) ? : list_entry(head, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_continue - continue iteration over list of given type ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Continue to iterate over list of given type, continuing after ++ * the current position. ++ */ ++#define list_for_each_entry_continue(pos, head, member) \ ++ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_continue_reverse - iterate backwards from the given point ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Start to iterate over list of given type backwards, continuing after ++ * the current position. ++ */ ++#define list_for_each_entry_continue_reverse(pos, head, member) \ ++ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.prev, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_from - iterate over list of given type from the current point ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate over list of given type, continuing from current position. ++ */ ++#define list_for_each_entry_from(pos, head, member) \ ++ for (; &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_for_each_entry_safe_continue ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate over list of given type, continuing after current point, ++ * safe against removal of list entry. ++ */ ++#define list_for_each_entry_safe_continue(pos, n, head, member) \ ++ for (pos = list_entry(pos->member.next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_for_each_entry_safe_from ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate over list of given type from current point, safe against ++ * removal of list entry. ++ */ ++#define list_for_each_entry_safe_from(pos, n, head, member) \ ++ for (n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_for_each_entry_safe_reverse ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Iterate backwards over list of given type, safe against removal ++ * of list entry. ++ */ ++#define list_for_each_entry_safe_reverse(pos, n, head, member) \ ++ for (pos = list_entry((head)->prev, typeof(*pos), member), \ ++ n = list_entry(pos->member.prev, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) ++ ++/* ++ * Double linked lists with a single pointer list head. ++ * Mostly useful for hash tables where the two pointer list head is ++ * too wasteful. ++ * You lose the ability to access the tail in O(1). ++ */ ++ ++struct hlist_head { ++ struct hlist_node *first; ++}; ++ ++struct hlist_node { ++ struct hlist_node *next, **pprev; ++}; ++ ++#define HLIST_HEAD_INIT { .first = NULL } ++#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } ++#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) ++static inline void INIT_HLIST_NODE(struct hlist_node *h) ++{ ++ h->next = NULL; ++ h->pprev = NULL; ++} ++ ++static inline int hlist_unhashed(const struct hlist_node *h) ++{ ++ return !h->pprev; ++} ++ ++static inline int hlist_empty(const struct hlist_head *h) ++{ ++ return !h->first; ++} ++ ++static inline void __hlist_del(struct hlist_node *n) ++{ ++ struct hlist_node *next = n->next; ++ struct hlist_node **pprev = n->pprev; ++ *pprev = next; ++ if (next) ++ next->pprev = pprev; ++} ++ ++static inline void hlist_del(struct hlist_node *n) ++{ ++ __hlist_del(n); ++ n->next = NULL; ++ n->pprev = NULL; ++} ++ ++static inline void hlist_del_init(struct hlist_node *n) ++{ ++ if (!hlist_unhashed(n)) { ++ __hlist_del(n); ++ INIT_HLIST_NODE(n); ++ } ++} ++ ++ ++static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) ++{ ++ struct hlist_node *first = h->first; ++ n->next = first; ++ if (first) ++ first->pprev = &n->next; ++ h->first = n; ++ n->pprev = &h->first; ++} ++ ++ ++/* next must be != NULL */ ++static inline void hlist_add_before(struct hlist_node *n, ++ struct hlist_node *next) ++{ ++ n->pprev = next->pprev; ++ n->next = next; ++ next->pprev = &n->next; ++ *(n->pprev) = n; ++} ++ ++static inline void hlist_add_after(struct hlist_node *n, ++ struct hlist_node *next) ++{ ++ next->next = n->next; ++ n->next = next; ++ next->pprev = &n->next; ++ ++ if(next->next) ++ next->next->pprev = &next->next; ++} ++ ++#define hlist_entry(ptr, type, member) container_of(ptr,type,member) ++ ++#define hlist_for_each(pos, head) \ ++ for (pos = (head)->first; pos; pos = pos->next) ++ ++#define hlist_for_each_safe(pos, n, head) \ ++ for (pos = (head)->first; pos; pos = n) ++ ++/** ++ * hlist_for_each_entry - iterate over list of given type ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry(tpos, pos, head, member) \ ++ for (pos = (head)->first; pos && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++/** ++ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry_continue(tpos, pos, member) \ ++ for (pos = (pos)->next; pos && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++/** ++ * hlist_for_each_entry_from - iterate over a hlist continuing from current point ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry_from(tpos, pos, member) \ ++ for (; pos && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = pos->next) ++ ++/** ++ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry ++ * @tpos: the type * to use as a loop cursor. ++ * @pos: the &struct hlist_node to use as a loop cursor. ++ * @n: another &struct hlist_node to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the hlist_node within the struct. ++ */ ++#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ ++ for (pos = (head)->first; \ ++ pos && ({ n = pos->next; 1; }) && \ ++ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ ++ pos = n) ++ ++#endif +Index: boa-0.94.13/src/plugin.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ boa-0.94.13/src/plugin.c 2008-05-27 19:28:21.000000000 +0200 +@@ -0,0 +1,189 @@ ++/* ++ * Simple plugin API for boa ++ * Copyright (C) 2008 John Crispin ++ * Copyright (C) 2008 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. ++ * ++ * 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include "boa.h" ++#include "list.h" ++#include ++#include ++ ++static LIST_HEAD(plugins); ++ ++struct httpd_plugin *plugin_lookup(request *req) ++{ ++ struct list_head *l; ++ list_for_each(l, &plugins) ++ { ++ struct httpd_plugin *p = ++ container_of(l, struct httpd_plugin, list); ++ ++ if (!strncmp(req->request_uri, p->prefix, strlen(p->prefix))) ++ return p; ++ } ++ return NULL; ++} ++ ++static int plugin_run(request *req, struct httpd_plugin *p) ++{ ++ struct http_context ctx; ++ int child_pid; ++ ++ SQUASH_KA(req); ++ ++ memset(&ctx, 0, sizeof(ctx)); ++ ctx.uri = req->request_uri; ++ switch(req->method) { ++ case M_POST: ++ ctx.request_method = "POST"; ++ break; ++ case M_HEAD: ++ ctx.request_method = "HEAD"; ++ break; ++ case M_GET: ++ ctx.request_method = "GET"; ++ break; ++ } ++ ctx.server_addr = req->local_ip_addr; ++ ctx.server_proto = req->http_version; ++ ctx.query_string = req->query_string; ++ ctx.remote_addr = req->remote_ip_addr; ++ ctx.remote_port = req->remote_port; ++ if (req->method == M_POST) { ++ if (req->content_type) ++ ctx.content_type = req->content_type; ++ else ++ ctx.content_type = default_type; ++ ctx.content_length = req->content_length; ++ } ++#ifdef ACCEPT_ON ++ if (req->accept[0]) ++ ctx.http_accept = req->accept; ++#endif ++ ++ p->prepare_req(p, &ctx); ++ child_pid = fork(); ++ ++ switch(child_pid) { ++ case -1: ++ log_error_time(); ++ perror("fork"); ++ send_r_error(req); ++ return 0; ++ ++ case 0: ++ if (dup2(req->fd, STDOUT_FILENO) == -1) { ++ log_error_time(); ++ perror("dup2 - fd"); ++ _exit(1); ++ } ++ if (set_block_fd(req->fd) == -1) { ++ log_error_time(); ++ perror("cgi-fcntl"); ++ _exit(1); ++ } ++ if (req->method == M_POST) { ++ dup2(req->read_data_fd, STDIN_FILENO); ++ close(req->read_data_fd); ++ close(req->post_data_fd); ++ set_block_fd(STDIN_FILENO); ++ } ++ close_access_log(); ++ ++ if (cgi_log_fd) ++ dup2(cgi_log_fd, STDERR_FILENO); ++ ++ p->handle_req(p, &ctx); ++ exit(0); ++ break; ++ } ++ ++ return 1; ++} ++ ++int plugin_handle(request * req) ++{ ++ struct httpd_plugin *p; ++ ++ p = plugin_lookup(req); ++ if (!p) ++ return 0; ++ ++ return plugin_run(req, p); ++} ++ ++static void plugin_load(const char *p, const char *dir) ++{ ++ struct httpd_plugin *plugin; ++ void *dl; ++ ++ /* ignore directories */ ++ if (p[strlen(p) - 1] == '/') ++ return; ++ ++ dl = dlopen(p, RTLD_NOW); ++ if (!dl) { ++ fprintf(stderr, "Unable to load plugin '%s': %d\n", p, dlerror()); ++ return; ++ } ++ ++ plugin = dlsym(dl, "httpd_plugin"); ++ if (!plugin) ++ goto error; ++ ++ INIT_LIST_HEAD(&plugin->list); ++ plugin->dir = dir; ++ ++ if (plugin->init(plugin) != 1) ++ goto error; ++ ++ if (!plugin->prefix) ++ goto error_init; ++ ++ list_add(&plugin->list, &plugins); ++ return; ++ ++error_init: ++ plugin->done(plugin); ++error: ++ fprintf(stderr, "Plugin '%s' failed to initialize\n", p); ++ dlclose(dl); ++} ++ ++#define WILDCARD_SUFFIX "/*.so" ++ ++int plugin_init(char *path) ++{ ++ int buflen = 128; ++ char *plugindir; ++ glob_t g; ++ char *s; ++ int i; ++ ++ s = malloc(strlen(path) + sizeof(WILDCARD_SUFFIX) + 1); ++ strcpy(s, path); ++ strcat(s, WILDCARD_SUFFIX); ++ glob(s, GLOB_MARK, NULL, &g); ++ free(s); ++ ++ for (i = 0; i < g.gl_pathc; i++) ++ plugin_load(g.gl_pathv[i], path); ++ ++ globfree(&g); ++} ++ ++ +Index: boa-0.94.13/src/request.c +=================================================================== +--- boa-0.94.13.orig/src/request.c 2002-07-24 05:03:59.000000000 +0200 ++++ boa-0.94.13/src/request.c 2008-05-27 19:28:21.000000000 +0200 +@@ -50,6 +50,7 @@ + dequeue(&request_free, request_free); /* dequeue the head */ + } else { + req = (request *) malloc(sizeof (request)); ++ memset(req, 0, sizeof(request)); + if (!req) { + log_error_time(); + perror("malloc for new request"); +@@ -603,6 +604,8 @@ + + int process_header_end(request * req) + { ++ int ret; ++ + if (!req->logline) { + send_r_error(req); + return 0; +@@ -630,11 +633,26 @@ + } + + if (req->method == M_POST) { +- req->post_data_fd = create_temporary_file(1, NULL, 0); +- if (req->post_data_fd == 0) +- return(0); +- return(1); /* success */ +- } ++ if (!req->plugin) { ++ req->post_data_fd = create_temporary_file(1, NULL, 0); ++ } else { ++ int fd[2]; ++ if (pipe(&fd[0]) != -1) { ++ req->post_data_fd = fd[1]; ++ req->read_data_fd = fd[0]; ++ set_nonblock_fd(req->post_data_fd); ++ } ++ } ++ if (req->post_data_fd == 0) { ++ return(0); ++ } ++ if (!req->plugin) ++ return(1); /* success */ ++ } ++ ++ ret = plugin_handle(req); ++ if (ret) ++ return ret; + + if (req->is_cgi) { + return init_cgi(req); +Index: boa-0.94.13/src/Makefile.in +=================================================================== +--- boa-0.94.13.orig/src/Makefile.in 2002-03-24 23:20:19.000000000 +0100 ++++ boa-0.94.13/src/Makefile.in 2008-05-27 19:28:21.000000000 +0200 +@@ -20,7 +20,7 @@ + srcdir = @srcdir@ + VPATH = @srcdir@:@srcdir@/../extras + LDFLAGS = @LDFLAGS@ +-LIBS = @LIBS@ ++LIBS = @LIBS@ -ldl + CFLAGS = @CFLAGS@ -I. + + # Change these if necessary +@@ -32,7 +32,8 @@ + + SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \ + get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c read.c \ +- request.c response.c select.c signals.c util.c sublog.c ++ request.c response.c select.c signals.c util.c sublog.c \ ++ plugin.c + + OBJS = y.tab.o lex.yy.o $(SOURCES:.c=.o) timestamp.o @STRUTIL@ + +Index: boa-0.94.13/src/boa.h +=================================================================== +--- boa-0.94.13.orig/src/boa.h 2002-07-26 05:03:44.000000000 +0200 ++++ boa-0.94.13/src/boa.h 2008-05-27 19:28:21.000000000 +0200 +@@ -37,6 +37,7 @@ + #include + #include /* OPEN_MAX */ + #include ++#include + + #include + #include +@@ -50,6 +51,7 @@ + #include "compat.h" /* oh what fun is porting */ + #include "defines.h" + #include "globals.h" ++#include "boa-plugin.h" + + /* alias */ + void add_alias(char *fakename, char *realname, int script); +@@ -192,4 +194,9 @@ + /* select */ + void select_loop(int server_s); + ++/* plugins */ ++int plugin_init(char *path); ++int plugin_handle(request * req); ++struct httpd_plugin *plugin_lookup(request *req); ++ + #endif +Index: boa-0.94.13/src/config.c +=================================================================== +--- boa-0.94.13.orig/src/config.c 2002-07-26 05:04:29.000000000 +0200 ++++ boa-0.94.13/src/config.c 2008-05-27 19:28:21.000000000 +0200 +@@ -61,6 +61,7 @@ + char *error_log_name; + char *access_log_name; + char *cgi_log_name; ++char *plugin_root = NULL; + + int use_localtime; + +@@ -116,6 +117,7 @@ + {"SinglePostLimit", S1A, c_set_int, &single_post_limit}, + {"CGIPath", S1A, c_set_string, &cgi_path}, + {"MaxConnections", S1A, c_set_int, &max_connections}, ++ {"PluginRoot", S1A, c_set_string, &plugin_root}, + }; + + static void c_set_user(char *v1, char *v2, void *t) +@@ -323,6 +325,22 @@ + free(dirmaker); + dirmaker = temp; + } ++ if (plugin_root) { ++ char *plugin_path = plugin_root; ++ char *next; ++ ++ do { ++ next = strchr(plugin_path, ':'); ++ if (next) { ++ *next = 0; ++ next++; ++ } ++ ++ plugin_init(normalize_path(plugin_path)); ++ plugin_path = next; ++ } while (plugin_path); ++ free(plugin_root); ++ } + + #if 0 + if (mime_types) { +Index: boa-0.94.13/src/alias.c +=================================================================== +--- boa-0.94.13.orig/src/alias.c 2002-07-28 04:46:52.000000000 +0200 ++++ boa-0.94.13/src/alias.c 2008-05-27 19:28:21.000000000 +0200 +@@ -213,6 +213,7 @@ + uri_len = strlen(req->request_uri); + + current = find_alias(req->request_uri, uri_len); ++ req->plugin = !!plugin_lookup(req); + if (current) { + + if (current->type == SCRIPTALIAS) /* Script */ +@@ -237,7 +238,7 @@ + } + + if (current->type == REDIRECT) { /* Redirect */ +- if (req->method == M_POST) { /* POST to non-script */ ++ if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */ + /* it's not a cgi, but we try to POST??? */ + send_r_bad_request(req); + return 0; /* not a script alias, therefore begin filling in data */ +@@ -361,7 +362,7 @@ + else + req->is_cgi = CGI; + return 1; +- } else if (req->method == M_POST) { /* POST to non-script */ ++ } else if ((req->method == M_POST) && !req->plugin) { /* POST to non-script */ + /* it's not a cgi, but we try to POST??? */ + send_r_bad_request(req); + return 0; +Index: boa-0.94.13/src/globals.h +=================================================================== +--- boa-0.94.13.orig/src/globals.h 2002-07-24 05:03:59.000000000 +0200 ++++ boa-0.94.13/src/globals.h 2008-05-27 19:28:21.000000000 +0200 +@@ -47,6 +47,7 @@ + struct request { /* pending requests */ + int fd; /* client's socket fd */ + int status; /* see #defines.h */ ++ bool plugin; + time_t time_last; /* time of last succ. op. */ + char *pathname; /* pathname of requested file */ + int simple; /* simple request? */ +@@ -92,6 +93,7 @@ + char *header_referer; + + int post_data_fd; /* fd for post data tmpfile */ ++ int read_data_fd; /* fd for post data input (plugin) */ + + char *path_info; /* env variable */ + char *path_translated; /* env variable */ +Index: boa-0.94.13/src/read.c +=================================================================== +--- boa-0.94.13.orig/src/read.c 2002-03-18 02:53:48.000000000 +0100 ++++ boa-0.94.13/src/read.c 2008-05-27 19:28:21.000000000 +0200 +@@ -338,8 +338,11 @@ + + if (bytes_to_write == 0) { /* nothing left in buffer to write */ + req->header_line = req->header_end = req->buffer; +- if (req->filepos >= req->filesize) +- return init_cgi(req); ++ if (req->filepos >= req->filesize) { ++ if (req->post_data_fd > 0) ++ close(req->post_data_fd); ++ return init_cgi(req); ++ } + /* if here, we can safely assume that there is more to read */ + req->status = BODY_READ; + return 1; +Index: boa-0.94.13/src/boa-plugin.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ boa-0.94.13/src/boa-plugin.h 2008-05-27 19:28:21.000000000 +0200 +@@ -0,0 +1,67 @@ ++#ifndef _HTTPD_PLUGIN_H__ ++#define _HTTPD_PLUGIN_H__ ++ ++#include "list.h" ++ ++/* ++ * Definition for HTTP server plugins ++ * ++ * The context that the plugin is called with for ++ * a single http request. It gets allocated in the ++ * persistent context before prepare_req and freed ++ * there afterwards (still active in the forked ++ * context at handle_req time) ++ */ ++struct http_context ++{ ++ char *uri; ++ char *request_method; ++ char *server_addr; ++ char *server_proto; ++ char *query_string; ++ char *remote_addr; ++ unsigned int remote_port; ++ char *content_type; ++ char *content_length; ++ char *http_accept; ++ ++ void *priv; ++}; ++ ++/* ++ * the main data structure of httpd plugins. ++ */ ++struct httpd_plugin ++{ ++ /* used by the web server */ ++ struct list_head list; ++ ++ /* only page requests matching 'prefix' are passed ++ * to prepare_req and handle_req */ ++ const char *prefix; ++ ++ /* directory that the plugin was found in */ ++ const char *dir; ++ ++ /* initialize the plugin, if the return value is nonzero, ++ * the plugin will not be used */ ++ int (*init)(struct httpd_plugin *); ++ ++ /* free all memory associated with the plugin */ ++ void (*done)(struct httpd_plugin *); ++ ++ /* prepare a page request. this is executed in the main context, ++ * so pay attention to memory usage. should not print any data ++ * to stdout */ ++ int (*prepare_req)(struct httpd_plugin *, struct http_context *); ++ ++ /* handle the request. can print output data to stdout */ ++ int (*handle_req)(struct httpd_plugin *, struct http_context *); ++ ++ /* pointer for private data structures of the plugin */ ++ void *priv; ++}; ++ ++#define HTTPD_PLUGIN struct httpd_plugin httpd_plugin = ++ ++#endif diff --git a/libs/sgi-webuci/luasrc/sgi/webuci.lua b/libs/sgi-webuci/luasrc/sgi/webuci.lua index 498bca921..2beff6907 100644 --- a/libs/sgi-webuci/luasrc/sgi/webuci.lua +++ b/libs/sgi-webuci/luasrc/sgi/webuci.lua @@ -28,8 +28,9 @@ module("luci.sgi.webuci", package.seeall) local status_set = false -- Initialize the environment -function initenv(env) +function initenv(env, vars) luci.http.env = env + luci.http.vars = vars end -- Returns the main dispatcher URL @@ -44,7 +45,7 @@ end -- Returns a table of all COOKIE, GET and POST Parameters function luci.http.formvalues() - return webuci.vars + return luci.http.vars end -- Gets form value from key diff --git a/libs/sgi-webuci/root/etc/boa/boa.conf b/libs/sgi-webuci/root/etc/boa/boa.conf new file mode 100644 index 000000000..ce1dfb294 --- /dev/null +++ b/libs/sgi-webuci/root/etc/boa/boa.conf @@ -0,0 +1,16 @@ +Port 8080 +ErrorLog /dev/stderr +AccessLog /dev/stderr +DocumentRoot ../../www +DirectoryMaker ../../usr/lib/boa/boa_indexer +KeepAliveMax 1000 +KeepAliveTimeout 10 +MimeTypes ../mime.types +DefaultType text/plain +CGIPath /bin:/usr/bin:/usr/local/bin:../../bin:../../usr/bin:../../usr/local/bin + +AddType application/x-httpd-cgi cgi +AddType application/x-httpd-cgi sh + +ScriptAlias /cgi-bin/ ../../www/cgi-bin +PluginRoot ../../usr/lib/boa diff --git a/libs/sgi-webuci/root/etc/mime.types b/libs/sgi-webuci/root/etc/mime.types new file mode 100644 index 000000000..ee11c1bfe --- /dev/null +++ b/libs/sgi-webuci/root/etc/mime.types @@ -0,0 +1,748 @@ +############################################################################### +# +# MIME-TYPES and the extensions that represent them +# +# This file is part of the "mime-support" package. Please send email (not a +# bug report) to mime-support@packages.debian.org if you would like new types +# and/or extensions to be added. +# +# The reason that all types are managed by the mime-support package instead +# allowing individual packages to install types in much the same way as they +# add entries in to the mailcap file is so these types can be referenced by +# other programs (such as a web server) even if the specific support package +# for that type is not installed. +# +# Users can add their own types if they wish by creating a ".mime.types" +# file in their home directory. Definitions included there will take +# precedence over those listed here. +# +# Note: Compression schemes like "gzip", "bzip", and "compress" are not +# actually "mime-types". They are "encodings" and hence must _not_ have +# entries in this file to map their extensions. The "mime-type" of an +# encoded file refers to the type of data that has been encoded, not the +# type of encoding. +# +############################################################################### + + +application/activemessage +application/andrew-inset ez +application/applefile +application/atom atom +application/atomcat+xml atomcat +application/atomserv+xml atomsrv +application/atomicmail +application/batch-SMTP +application/beep+xml +application/cals-1840 +application/cap cap pcap +application/commonground +application/cu-seeme cu +application/cybercash +application/dca-rft +application/dec-dx +application/docbook+xml +application/dsptype tsp +application/dvcs +application/edi-consent +application/edi-x12 +application/edifact +application/eshop +application/font-tdpfr +application/futuresplash spl +application/ghostview +application/hta hta +application/http +application/hyperstudio +application/iges +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc +application/mathematica nb +application/mathematica-old +application/ms-tnef +application/msaccess mdb +application/msword doc dot +application/news-message-id +application/news-transmission +application/ocsp-request +application/ocsp-response +application/octet-stream bin +application/oda oda +application/ogg ogg +application/parityfec +application/pdf pdf +application/pgp-encrypted +application/pgp-keys key +application/pgp-signature pgp +application/pics-rules prf +application/pkcs10 +application/pkcs7-mime +application/pkcs7-signature +application/pkix-cert +application/pkix-crl +application/pkixcmp +application/postscript ps ai eps +application/prs.alvestrand.titrax-sheet +application/prs.cww +application/prs.nprend +application/qsig +application/rar rar +application/rdf+xml rdf +application/remote-printing +application/riscos +application/rss+xml rss +application/rtf rtf +application/sdp +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog +application/sieve +application/slate +application/smil smi smil +application/timestamp-query +application/timestamp-reply +application/vemmi +application/whoispp-query +application/whoispp-response +application/wita +application/wordperfect wpd +application/wordperfect5.1 wp5 +application/x400-bp +application/xhtml+xml xhtml xht +application/xml xml xsl +application/xml-dtd +application/xml-external-parsed-entity +application/zip zip +application/vnd.3M.Post-it-Notes +application/vnd.accpac.simply.aso +application/vnd.accpac.simply.imp +application/vnd.acucobol +application/vnd.aether.imp +application/vnd.anser-web-certificate-issue-initiation +application/vnd.anser-web-funds-transfer-initiation +application/vnd.audiograph +application/vnd.bmi +application/vnd.businessobjects +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cinderella cdy +application/vnd.claymore +application/vnd.commerce-battelle +application/vnd.commonspace +application/vnd.comsocaller +application/vnd.contact.cmsg +application/vnd.cosmocaller +application/vnd.ctc-posml +application/vnd.cups-postscript +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.cybank +application/vnd.dna +application/vnd.dpgraph +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven +application/vnd.epson.esf +application/vnd.epson.msf +application/vnd.epson.quickanime +application/vnd.epson.salt +application/vnd.epson.ssf +application/vnd.ericsson.quickcall +application/vnd.eudora.data +application/vnd.fdf +application/vnd.ffsns +application/vnd.flographit +application/vnd.framemaker +application/vnd.fsc.weblaunch +application/vnd.fujitsu.oasys +application/vnd.fujitsu.oasys2 +application/vnd.fujitsu.oasys3 +application/vnd.fujitsu.oasysgp +application/vnd.fujitsu.oasysprs +application/vnd.fujixerox.ddd +application/vnd.fujixerox.docuworks +application/vnd.fujixerox.docuworks.binder +application/vnd.fut-misnet +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq +application/vnd.groove-account +application/vnd.groove-identity-message +application/vnd.groove-injector +application/vnd.groove-tool-message +application/vnd.groove-tool-template +application/vnd.groove-vcard +application/vnd.hhe.lesson-player +application/vnd.hp-HPGL +application/vnd.hp-PCL +application/vnd.hp-PCLXL +application/vnd.hp-hpid +application/vnd.hp-hps +application/vnd.httphone +application/vnd.hzn-3d-crossword +application/vnd.ibm.MiniPay +application/vnd.ibm.afplinedata +application/vnd.ibm.modcap +application/vnd.informix-visionary +application/vnd.intercon.formnet +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo +application/vnd.intu.qfx +application/vnd.irepository.package+xml +application/vnd.is-xpr +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.koan +application/vnd.lotus-1-2-3 +application/vnd.lotus-approach +application/vnd.lotus-freelance +application/vnd.lotus-notes +application/vnd.lotus-organizer +application/vnd.lotus-screencam +application/vnd.lotus-wordpro +application/vnd.mcd +application/vnd.mediastation.cdkey +application/vnd.meridian-slingshot +application/vnd.mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf +application/vnd.mobius.dis +application/vnd.mobius.msl +application/vnd.mobius.plc +application/vnd.mobius.txf +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry +application/vnd.ms-asf +application/vnd.ms-excel xls xlb xlt +application/vnd.ms-lrm +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +application/vnd.ms-powerpoint ppt pps +application/vnd.ms-project +application/vnd.ms-tnef +application/vnd.ms-works +application/vnd.mseq +application/vnd.msign +application/vnd.music-niff +application/vnd.musician +application/vnd.netfpx +application/vnd.noblenet-directory +application/vnd.noblenet-sealer +application/vnd.noblenet-web +application/vnd.novadigm.EDM +application/vnd.novadigm.EDX +application/vnd.novadigm.EXT +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.osa.netdeploy +application/vnd.palm +application/vnd.pg.format +application/vnd.pg.osasli +application/vnd.powerbuilder6 +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.previewsystems.box +application/vnd.publishare-delta-tree +application/vnd.pvi.ptid1 +application/vnd.pwg-xhtml-print+xml +application/vnd.rapid +application/vnd.rim.cod cod +application/vnd.s3sms +application/vnd.seemail +application/vnd.shana.informed.formdata +application/vnd.shana.informed.formtemplate +application/vnd.shana.informed.interchange +application/vnd.shana.informed.package +application/vnd.smaf mmf +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.chart sds +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math sdf +application/vnd.stardivision.writer sdw +application/vnd.stardivision.writer-global sgl +application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.symbian.install sis +application/vnd.triscape.mxs +application/vnd.trueapp +application/vnd.truedoc +application/vnd.tve-trigger +application/vnd.ufdl +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio vsd +application/vnd.vividence.scriptfile +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf +application/vnd.xara +application/vnd.xfdl +application/vnd.yellowriver-custom-menu +application/x-123 wk +application/x-7z-compressed 7z +application/x-abiword abw +application/x-apple-diskimage dmg +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-cab cab +application/x-cbr cbr +application/x-cbz cbz +application/x-cdf cdf +application/x-cdlink vcd +application/x-chess-pgn pgn +application/x-core +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-director dcr dir dxr +application/x-dms dms +application/x-doom wad +application/x-dvi dvi +application/x-httpd-eruby rhtml +application/x-executable +application/x-flac flac +application/x-font pfa pfb gsf pcf pcf.Z +application/x-freemind mm +application/x-futuresplash spl +application/x-gnumeric gnumeric +application/x-go-sgf sgf +application/x-graphing-calculator gcf +application/x-gtar gtar tgz taz +application/x-hdf hdf +application/x-httpd-php phtml pht php +application/x-httpd-php-source phps +application/x-httpd-php3 php3 +application/x-httpd-php3-preprocessed php3p +application/x-httpd-php4 php4 +application/x-ica ica +application/x-internet-signup ins isp +application/x-iphone iii +application/x-iso9660-image iso +application/x-java-applet +application/x-java-bean +application/x-java-jnlp-file jnlp +application/x-javascript js +application/x-jmol jmz +application/x-kchart chrt +application/x-kdelnk +application/x-killustrator kil +application/x-koan skp skd skt skm +application/x-kpresenter kpr kpt +application/x-kspread ksp +application/x-kword kwd kwt +application/x-latex latex +application/x-lha lha +application/x-lyx lyx +application/x-lzh lzh +application/x-lzx lzx +application/x-maker frm maker frame fm fb book fbdoc +application/x-mif mif +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-msdos-program com exe bat dll +application/x-msi msi +application/x-netcdf nc +application/x-ns-proxy-autoconfig pac +application/x-nwc nwc +application/x-object o +application/x-oz-application oza +application/x-pkcs7-certreqresp p7r +application/x-pkcs7-crl crl +application/x-python-code pyc pyo +application/x-quicktimeplayer qtl +application/x-redhat-package-manager rpm +application/x-rx +application/x-sh sh +application/x-shar shar +application/x-shellscript +application/x-shockwave-flash swf swfl +application/x-stuffit sit sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex-gf gf +application/x-tex-pk pk +application/x-texinfo texinfo texi +application/x-trash ~ % bak old sik +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-videolan +application/x-wais-source src +application/x-wingz wz +application/x-x509-ca-cert crt +application/x-xcf xcf +application/x-xfig fig +application/x-xpinstall xpi + +audio/32kadpcm +audio/3gpp +audio/basic au snd +audio/g.722.1 +audio/l16 +audio/midi mid midi kar +audio/mp4a-latm +audio/mpa-robust +audio/mpeg mpga mpega mp2 mp3 m4a +audio/mpegurl m3u +audio/parityfec +audio/prs.sid sid +audio/telephone-event +audio/tone +audio/vnd.cisco.nse +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds +audio/vnd.everad.plj +audio/vnd.lucent.voice +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 +audio/vnd.nuera.ecelp7470 +audio/vnd.nuera.ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.vmx.cvsd +audio/x-aiff aif aiff aifc +audio/x-gsm gsm +audio/x-mpegurl m3u +audio/x-ms-wma wma +audio/x-ms-wax wax +audio/x-pn-realaudio-plugin +audio/x-pn-realaudio ra rm ram +audio/x-realaudio ra +audio/x-scpls pls +audio/x-sd2 sd2 +audio/x-wav wav + +chemical/x-alchemy alc +chemical/x-cache cac cache +chemical/x-cache-csf csf +chemical/x-cactvs-binary cbin cascii ctab +chemical/x-cdx cdx +chemical/x-cerius cer +chemical/x-chem3d c3d +chemical/x-chemdraw chm +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-compass cpa +chemical/x-crossfire bsd +chemical/x-csml csml csm +chemical/x-ctx ctx +chemical/x-cxf cxf cef +#chemical/x-daylight-smiles smi +chemical/x-embl-dl-nucleotide emb embl +chemical/x-galactic-spc spc +chemical/x-gamess-input inp gam gamin +chemical/x-gaussian-checkpoint fch fchk +chemical/x-gaussian-cube cub +chemical/x-gaussian-input gau gjc gjf +chemical/x-gaussian-log gal +chemical/x-gcg8-sequence gcg +chemical/x-genbank gen +chemical/x-hin hin +chemical/x-isostar istr ist +chemical/x-jcamp-dx jdx dx +chemical/x-kinemage kin +chemical/x-macmolecule mcm +chemical/x-macromodel-input mmd mmod +chemical/x-mdl-molfile mol +chemical/x-mdl-rdfile rd +chemical/x-mdl-rxnfile rxn +chemical/x-mdl-sdfile sd sdf +chemical/x-mdl-tgf tgf +#chemical/x-mif mif +chemical/x-mmcif mcif +chemical/x-mol2 mol2 +chemical/x-molconn-Z b +chemical/x-mopac-graph gpt +chemical/x-mopac-input mop mopcrt mpc dat zmt +chemical/x-mopac-out moo +chemical/x-mopac-vib mvb +chemical/x-ncbi-asn1 asn +chemical/x-ncbi-asn1-ascii prt ent +chemical/x-ncbi-asn1-binary val aso +chemical/x-ncbi-asn1-spec asn +chemical/x-pdb pdb ent +chemical/x-rosdal ros +chemical/x-swissprot sw +chemical/x-vamas-iso14976 vms +chemical/x-vmd vmd +chemical/x-xtel xtel +chemical/x-xyz xyz + +image/cgm +image/g3fax +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/naplps +image/pcx pcx +image/png png +image/prs.btif +image/prs.pti +image/svg+xml svg svgz +image/tiff tiff tif +image/vnd.cns.inf2 +image/vnd.djvu djvu djv +image/vnd.dwg +image/vnd.dxf +image/vnd.fastbidsheet +image/vnd.fpx +image/vnd.fst +image/vnd.fujixerox.edmics-mmr +image/vnd.fujixerox.edmics-rlc +image/vnd.mix +image/vnd.net-fpx +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff +image/x-cmu-raster ras +image/x-coreldraw cdr +image/x-coreldrawpattern pat +image/x-coreldrawtemplate cdt +image/x-corelphotopaint cpt +image/x-icon ico +image/x-jg art +image/x-jng jng +image/x-ms-bmp bmp +image/x-photoshop psd +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd + +inode/chardevice +inode/blockdevice +inode/directory-locked +inode/directory +inode/fifo +inode/socket + +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/s-http +message/news +message/partial +message/rfc822 eml + +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf +model/vnd.flatland.3dml +model/vnd.gdl +model/vnd.gs-gdl +model/vnd.gtw +model/vnd.mts +model/vnd.vtu +model/vrml wrl vrml + +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message + +text/calendar ics icz +text/css css +text/csv csv +text/directory +text/english +text/enriched +text/h323 323 +text/html html htm shtml +text/iuls uls +text/mathml mml +text/parityfec +text/plain asc txt text pot +text/prs.lines.tag +text/rfc822-headers +text/richtext rtx +text/rtf +text/scriptlet sct wsc +text/t140 +text/texmacs tm ts +text/tab-separated-values tsv +text/uri-list +text/vnd.abc +text/vnd.curl +text/vnd.DMClientScript +text/vnd.flatland.3dml +text/vnd.fly +text/vnd.fmi.flexstor +text/vnd.in3d.3dml +text/vnd.in3d.spot +text/vnd.IPTC.NewsML +text/vnd.IPTC.NITF +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.sun.j2me.app-descriptor jad +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-bibtex bib +text/x-boo boo +text/x-c++hdr h++ hpp hxx hh +text/x-c++src c++ cpp cxx cc +text/x-chdr h +text/x-component htc +text/x-crontab +text/x-csh csh +text/x-csrc c +text/x-dsrc d +text/x-diff diff patch +text/x-haskell hs +text/x-java java +text/x-literate-haskell lhs +text/x-makefile +text/x-moc moc +text/x-pascal p pas +text/x-pcs-gcd gcd +text/x-perl pl pm +text/x-python py +text/x-server-parsed-html +text/x-setext etx +text/x-sh sh +text/x-tcl tcl tk +text/x-tex tex ltx sty cls +text/x-vcalendar vcs +text/x-vcard vcf + +video/3gpp 3gp +video/dl dl +video/dv dif dv +video/fli fli +video/gl gl +video/mpeg mpeg mpg mpe +video/mp4 mp4 +video/quicktime qt mov +video/mp4v-es +video/parityfec +video/pointer +video/vnd.fvt +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu +video/vnd.mts +video/vnd.nokia.interleaved-multimedia +video/vnd.vivo +video/x-la-asf lsf lsx +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie + +x-conference/x-cooltalk ice + +x-epoc/x-sisx-app sisx +x-world/x-vrml vrm vrml wrl diff --git a/libs/sgi-webuci/root/lib/webuci/main.lua b/libs/sgi-webuci/root/lib/webuci/main.lua deleted file mode 100644 index cb2730d14..000000000 --- a/libs/sgi-webuci/root/lib/webuci/main.lua +++ /dev/null @@ -1,20 +0,0 @@ -module("webuci", package.seeall) - -function prepare_req(uri) - require("luci.dispatcher").createindex() - env = {} - env.REQUEST_URI = uri -end - -function handle_req(context) - env.SERVER_PROTOCOL = context.server_proto - env.REMOTE_ADDR = context.remote_addr - env.REQUEST_METHOD = context.request_method - env.PATH_INFO = context.uri - env.REMOTE_PORT = context.remote_port - env.SERVER_ADDR = context.server_addr - env.SCRIPT_NAME = env.REQUEST_URI:sub(1, #env.REQUEST_URI - #env.PATH_INFO) - - luci.sgi.webuci.initenv(env) - luci.dispatcher.httpdispatch() -end \ No newline at end of file diff --git a/libs/sgi-webuci/root/usr/lib/boa/luci.lua b/libs/sgi-webuci/root/usr/lib/boa/luci.lua new file mode 100644 index 000000000..2ea6ba4cb --- /dev/null +++ b/libs/sgi-webuci/root/usr/lib/boa/luci.lua @@ -0,0 +1,61 @@ +module("luci-plugin", package.seeall) + +function normalize(path) + local newpath + while newpath ~= path do + if (newpath) then + path = newpath + end + newpath = string.gsub(path, "/[^/]+/../", "/") + end + return newpath +end + +function init(path) + -- NB: path points to ROOT/usr/lib/boa, change it to /usr/lib/lua + root = normalize(path .. '/../../../') + path = normalize(path .. '/../lua/') + package.cpath = path..'?.so;'..package.cpath + package.path = path..'?.lua;'..package.path + + require("luci.dispatcher") + require("luci.sgi.webuci") + require("uci") + + if (root ~= '/') then + -- Entering dummy mode + uci.set_savedir(root..'/tmp/.uci') + uci.set_confdir(root..'/etc/config') + + luci.sys.hostname = function() return "" end + luci.sys.loadavg = function() return 0,0,0,0,0 end + luci.sys.reboot = function() return end + luci.sys.sysinfo = function() return "","","" end + luci.sys.syslog = function() return "" end + + luci.sys.net.arptable = function() return {} end + luci.sys.net.devices = function() return {} end + luci.sys.net.routes = function() return {} end + luci.sys.wifi.getiwconfig = function() return {} end + luci.sys.wifi.iwscan = function() return {} end + end +end + +function prepare_req(uri) + luci.dispatcher.createindex() + env = {} + env.REQUEST_URI = uri +end + +function handle_req(context) + env.SERVER_PROTOCOL = context.server_proto + env.REMOTE_ADDR = context.remote_addr + env.REQUEST_METHOD = context.request_method + env.PATH_INFO = context.uri + env.REMOTE_PORT = context.remote_port + env.SERVER_ADDR = context.server_addr + env.SCRIPT_NAME = env.REQUEST_URI:sub(1, #env.REQUEST_URI - #env.PATH_INFO) + + luci.sgi.webuci.initenv(env, vars) + luci.dispatcher.httpdispatch() +end diff --git a/libs/sgi-webuci/src/cgi.c b/libs/sgi-webuci/src/cgi.c new file mode 100644 index 000000000..f8bf4045e --- /dev/null +++ b/libs/sgi-webuci/src/cgi.c @@ -0,0 +1,530 @@ +/* + * CGI routines for luci + * Copyright (C) 2008 Felix Fietkau + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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 General Public License for more details. + */ + +/* + * Based on code from cgilib: + * + * cgi.c - Some simple routines for CGI programming + * Copyright (c) 1996-9,2007,8 Martin Schulze + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +static char * +cgiGetLine (FILE *stream) +{ + static char *line = NULL; + static size_t size = 0; + char buf[BUFSIZE]; + char *cp; + + if (!line) { + if ((line = (char *)malloc (BUFSIZE)) == NULL) + return NULL; + size = BUFSIZE; + } + line[0] = '\0'; + + while (!feof (stream)) { + if ((cp = fgets (buf, sizeof (buf), stream)) == NULL) + return NULL; + + if (strlen(line)+strlen(buf)+1 > size) { + if ((cp = (char *)realloc (line, size + BUFSIZE)) == NULL) + return line; + size += BUFSIZE; + line = cp; + } + + strcat (line, buf); + if (line[strlen(line)-1] == '\n') { + line[strlen(line)-1] = '\0'; + if (line[strlen(line)-1] == '\r') + line[strlen(line)-1] = '\0'; + return line; + } + } + + return NULL; +} + + +static const char * +luci_getenv(lua_State *L, const char *name) +{ + const char *ret; + + lua_getfield(L, lua_upvalueindex(2), name); + ret = lua_tostring(L, -1); + lua_pop(L, 1); + return ret; +} + +static void +luci_setvar(lua_State *L, const char *name, const char *value, bool append) +{ + /* Check if there is an existing value already */ + lua_getfield(L, lua_upvalueindex(1), name); + if (lua_isnil(L, -1)) { + /* nope, we're safe - add a new one */ + lua_pushstring(L, value); + lua_setfield(L, lua_upvalueindex(1), name); + } else if (lua_istable(L, -1) && append) { + /* it's a table already, but appending is requested + * take the last element and append the new string to it */ + int tlast = lua_objlen(L, -1); + lua_rawgeti(L, -1, tlast); + lua_pushstring(L, value); + lua_pushstring(L, "\n"); + lua_concat(L, 3); + lua_rawseti(L, -2, tlast); + } else if (lua_istable(L, -1)) { + /* it's a table, which means we already have two + * or more entries, add the next one */ + + int tnext = lua_objlen(L, -1) + 1; /* next entry */ + + lua_pushstring(L, value); + luaL_setn(L, -2, tnext); + lua_rawseti(L, -2, tnext); + } else if (lua_isstring(L, -1) && append) { + /* append the new string to the existing variable */ + lua_pushstring(L, value); + lua_pushstring(L, "\n"); + lua_concat(L, 3); + lua_setfield(L, lua_upvalueindex(1), name); + } else if (lua_isstring(L, -1)) { + /* we're trying to add a variable that already has + * a string value. convert the string value to a + * table and add our new value to the table as well + */ + lua_createtable(L, 2, 0); + lua_pushvalue(L, -2); /* copy of the initial string value */ + lua_rawseti(L, -2, 1); + + lua_pushstring(L, value); + lua_rawseti(L, -2, 2); + lua_setfield(L, lua_upvalueindex(1), name); + } else { + luaL_error(L, "Invalid table entry type for index '%s'", name); + } +} + +char *cgiDecodeString (char *text) +{ + char *cp, *xp; + + for (cp=text,xp=text; *cp; cp++) { + if (*cp == '%') { + if (strchr("0123456789ABCDEFabcdef", *(cp+1)) + && strchr("0123456789ABCDEFabcdef", *(cp+2))) { + if (islower(*(cp+1))) + *(cp+1) = toupper(*(cp+1)); + if (islower(*(cp+2))) + *(cp+2) = toupper(*(cp+2)); + *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16 + + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0'); + xp++;cp+=2; + } + } else { + *(xp++) = *cp; + } + } + memset(xp, 0, cp-xp); + return text; +} + +#if 0 +/* cgiReadFile() + * + * Read and save a file fro a multipart request + */ +#include +char *cgiReadFile (FILE *stream, char *boundary) +{ + char *crlfboundary, *buf; + size_t boundarylen; + int c; + unsigned int pivot; + char *cp; + char template[]= "/tmp/cgilibXXXXXX"; + FILE *tmpfile; + int fd; + + boundarylen = strlen(boundary)+3; + if ((crlfboundary = (char *)malloc (boundarylen)) == NULL) + return NULL; + sprintf (crlfboundary, "\r\n%s", boundary); + + if ((buf = (char *)malloc (boundarylen)) == NULL) { + free (crlfboundary); + return NULL; + } + memset (buf, 0, boundarylen); + pivot = 0; + + if ((fd = mkstemp (template)) == -1) { + free (crlfboundary); + free (buf); + return NULL; + } + + if ((tmpfile = fdopen (fd, "w")) == NULL) { + free (crlfboundary); + free (buf); + unlink (template); + return NULL; + } + + while (!feof (stream)) { + c = fgetc (stream); + + if (c == 0) { + if (strlen (buf)) { + for (cp=buf; *cp; cp++) + putc (*cp, tmpfile); + memset (buf, 0, boundarylen); + pivot = 0; + } + putc (c, tmpfile); + continue; + } + + if (strlen (buf)) { + if (crlfboundary[pivot+1] == c) { + buf[++pivot] = c; + + if (strlen (buf) == strlen (crlfboundary)) + break; + else + continue; + } else { + for (cp=buf; *cp; cp++) + putc (*cp, tmpfile); + memset (buf, 0, boundarylen); + pivot = 0; + } + } + + if (crlfboundary[0] == c) { + buf[0] = c; + } else { + fputc (c, tmpfile); + } + } + + if (!feof (stream)) + fgets (buf, boundarylen, stream); + + fclose (tmpfile); + + free (crlfboundary); + free (buf); + + return strdup (template); +} +#endif + +/* + * Decode multipart/form-data + */ +#define MULTIPART_DELTA 5 +void luci_parse_multipart (lua_State *L, char *boundary) +{ + char *line; + char *cp, *xp; + char *name = NULL, *type = NULL; + char *fname = NULL; + int header = 1; + bool append = false; + + while ((line = cgiGetLine (stdin)) != NULL) { + if (!strncmp (line, boundary, strlen(boundary))) { + header = 1; + if (name) + free(name); + if (type) + free(type); + name = NULL; + type = NULL; + append = false; + } else if (header && !name && !strncasecmp (line, "Content-Disposition: form-data; ", 32)) { + if ((cp = strstr (line, "name=\"")) == NULL) + continue; + cp += 6; + if ((xp = strchr (cp, '\"')) == NULL) + continue; + name = malloc(xp-cp + 1); + strncpy(name, cp, xp-cp); + name[xp-cp] = 0; + cgiDecodeString (name); + + if ((cp = strstr (line, "filename=\"")) == NULL) + continue; + cp += 10; + if ((xp = strchr (cp, '\"')) == NULL) + continue; + fname = malloc(xp-cp + 1); + strncpy(fname, cp, xp-cp); + fname[xp-cp] = 0; + cgiDecodeString (fname); + } else if (header && !type && !strncasecmp (line, "Content-Type: ", 14)) { + cp = line + 14; + type = strdup (cp); + } else if (header) { + if (!strlen(line)) { + header = 0; + + if (fname) { +#if 0 + header = 1; + tmpfile = cgiReadFile (stdin, boundary); + + if (!tmpfile) { + free (name); + free (fname); + if (type) + free (type); + name = fname = type = NULL; + } + + cgiDebugOutput (2, "Wrote %s (%s) to file: %s", name, fname, tmpfile); + + if (!strlen (fname)) { + cgiDebugOutput (3, "Found empty filename, removing"); + unlink (tmpfile); + free (tmpfile); + free (name); + free (fname); + if (type) + free (type); + name = fname = type = NULL; + } else { + if ((file = (s_file *)malloc (sizeof (s_file))) == NULL) { + cgiDebugOutput (3, "malloc failed, ignoring %s=%s", name, fname); + unlink (tmpfile); + free (tmpfile); + free (name); + free (fname); + if (type) + free (type); + name = fname = type = NULL; + continue; + } + + file->name = name; + file->type = type; + file->tmpfile = tmpfile; + if ((cp = rindex (fname, '/')) == NULL) + file->filename = fname; + else { + file->filename = strdup (++cp); + free (fname); + } + name = type = fname = NULL; + + if (!files) { + if ((files = (s_file **)malloc(2*sizeof (s_file *))) == NULL) { + cgiDebugOutput (3, "malloc failed, ignoring %s=%s", name, fname); + unlink (tmpfile); + free (tmpfile); + free (name); + name = NULL; + if (type) { + free (type); + type = NULL; + } + free (file->filename); + free (file); + continue; + } + memset (files, 0, 2*sizeof (s_file *)); + index = 0; + } else { + for (index=0; files[index]; index++); + if ((tmpf = (s_file **)realloc(files, (index+2)*sizeof (s_file *))) == NULL) { + cgiDebugOutput (3, "realloc failed, ignoring %s=%s", name, fname); + unlink (tmpfile); + free (tmpfile); + free (name); + if (type) + free (type); + free (file->filename); + free (file); + name = type = fname = NULL; + continue; + } + files = tmpf; + memset (files + index, 0, 2*sizeof (s_file *)); + } + files[index] = file; + } +#else + free(fname); + fname = NULL; +#endif + } + } + } else { + if (!name) + return; + + cgiDecodeString(line); + luci_setvar(L, name, line, append); + if (!append) /* beginning of variable contents */ + append = true; + } + } +} + +/* parse the request header and store variables + * in the array supplied as function argument 1 on the stack + */ +int luci_parse_header (lua_State *L) +{ + int length; + char *line = NULL; + int numargs; + char *cp = NULL, *ip = NULL, *esp = NULL; + const char *ct, *il; + int i; + + if (!lua_istable(L, lua_upvalueindex(1))) + luaL_error(L, "Invalid argument"); + + if (!lua_istable(L, lua_upvalueindex(2))) + luaL_error(L, "Invalid argument"); + + ct = luci_getenv(L, "content_type"); + if (ct) { + ct = cp = strdup(ct); + } + if (cp && strstr(cp, "multipart/form-data") && strstr(cp, "boundary=")) { + cp = strstr(cp, "boundary=") + strlen ("boundary=") - 2; + *cp = *(cp+1) = '-'; + luci_parse_multipart(L, cp); + free((char *) ct); + return 0; + } + free((char *) ct); + + ct = luci_getenv(L, "request_method"); + il = luci_getenv(L, "content_length"); + + if (!ct) { + fprintf(stderr, "no request method!\n"); + return 0; + } + + if (!strcmp(ct, "POST")) { + if (il) { + length = atoi(il); + if (length <= 0) + return 0; + line = (char *)malloc (length+2); + if (line) + fgets(line, length+1, stdin); + } + } else if (!strcmp(ct, "GET")) { + ct = luci_getenv(L, "query_string"); + if (ct) + esp = strdup(ct); + if (esp && strlen(esp)) { + line = (char *)malloc (strlen(esp)+2); + if (line) + strcpy (line, esp); + } + free(esp); + } + + if (!line) + return 0; + + /* + * From now on all cgi variables are stored in the variable line + * and look like foo=bar&foobar=barfoo&foofoo= + */ + for (cp=line; *cp; cp++) + if (*cp == '+') + *cp = ' '; + + if (strlen(line)) { + for (numargs=1,cp=line; *cp; cp++) + if (*cp == '&' || *cp == ';' ) numargs++; + } else + numargs = 0; + + cp = line; + i=0; + while (*cp) { + char *name; + char *value; + + if ((ip = (char *)strchr(cp, '&')) != NULL) { + *ip = '\0'; + } else if ((ip = (char *)strchr(cp, ';')) != NULL) { + *ip = '\0'; + } else + ip = cp + strlen(cp); + + if ((esp=(char *)strchr(cp, '=')) == NULL) + goto skip; + + if (!strlen(esp)) + goto skip; + + if (i >= numargs) + goto skip; + + esp[0] = 0; + name = cp; + cgiDecodeString (name); + + cp = ++esp; + value = cp; + cgiDecodeString (value); + + luci_setvar(L, name, value, false); +skip: + cp = ++ip; + } + free(line); + return 0; +} + diff --git a/libs/sgi-webuci/src/luci.c b/libs/sgi-webuci/src/luci.c new file mode 100644 index 000000000..d65fc20b6 --- /dev/null +++ b/libs/sgi-webuci/src/luci.c @@ -0,0 +1,216 @@ +/* + * luci + * Copyright (C) 2008 John Crispin + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LUAMAIN "luci.lua" + +static lua_State *L = NULL; + +extern int luci_parse_header (lua_State *L); + +static int luci_init(struct httpd_plugin *p) +{ + char *path = NULL; + int ret = 0; + + L = luaL_newstate(); + if (!L) + goto error; + + luaL_openlibs(L); + + path = malloc(strlen(p->dir) + sizeof(LUAMAIN) + 2); + strcpy(path, p->dir); + strcat(path, "/" LUAMAIN); + + ret = luaL_dofile(L, path); + + lua_getfield(L, LUA_GLOBALSINDEX, "luci-plugin"); + do { + if (!lua_istable(L, -1)) { + ret = 1; + break; + } + + lua_getfield(L, -1, "init"); + if (!lua_isfunction(L, -1)) + break; + + lua_pushstring(L, p->dir); + ret = lua_pcall(L, 1, 0, 0); + } while (0); + free(path); + + if (ret != 0) + goto error; + + return 1; + +error: + fprintf(stderr, "Error: "); + if (L) { + const char *s = lua_tostring(L, -1); + if (!s) + s = "unknown error"; + fprintf(stderr, "%s\n", s); + lua_close(L); + } else { + fprintf(stderr, "Out of memory!\n"); + } + return 0; +} + +static void pushvar(char *name, char *val) +{ + if (!val) + return; + + lua_pushstring(L, val); + lua_setfield(L, -2, name); +} + +static int luci_pcall(lua_State *L, char *func, int narg) +{ + int ret; + + ret = lua_pcall(L, narg, narg, 0); + if (ret) { + const char *s = lua_tostring(L, -1); + if (s) + fprintf(stderr, "Error running %s: %s\n", func, s); + return ret; + } + if (!narg) + return ret; + + ret = lua_isnumber(L, -1); + if (!ret) + goto done; + + ret = lua_tonumber(L, -1); + +done: + lua_pop(L, 1); + return ret; +} + +static int luci_prepare_req(struct httpd_plugin *p, struct http_context *ctx) +{ + int ret; + + lua_getglobal(L, "luci-plugin"); + lua_getfield(L, -1, "prepare_req"); + + ret = lua_isfunction(L, -1); + if (!ret) + goto done; + + lua_pushstring(L, ctx->uri); + + ret = luci_pcall(L, "prepare_req", 1); + +done: + lua_pop(L, 1); + return ret; +} + +static int luci_handle_req(struct httpd_plugin *p, struct http_context *ctx) +{ + int ret; + + lua_newtable(L); /* new table for the http context */ + + /* convert http_context data structure to lua table */ +#define PUSH(x) pushvar(#x, ctx->x) + PUSH(request_method); + PUSH(server_addr); + PUSH(server_proto); + PUSH(query_string); + PUSH(remote_addr); + lua_pushinteger(L, ctx->remote_port); + lua_setfield(L, -2, "remote_port"); + PUSH(content_type); + PUSH(content_length); + PUSH(http_accept); +#undef PUSH + + if (!strncmp(ctx->uri, p->prefix, strlen(p->prefix))) + pushvar("uri", ctx->uri + strlen(p->prefix)); + else + pushvar("uri", ctx->uri); + + + /* make sure the global 'luci' table is prepared */ + lua_getglobal(L, "luci-plugin"); + if (!lua_istable(L, -1)) + return 0; + + lua_getfield(L, -1, "init_req"); + if (!lua_isfunction(L, -1)) { + /* ignore error */ + lua_pop(L, 1); + } else { + lua_pushvalue(L, -3); + luci_pcall(L, "init_req", 1); + } + + /* storage space for cgi variables */ + lua_newtable(L); + lua_pushvalue(L, -1); /* copy for setfield */ + lua_setfield(L, -3, "vars"); + + lua_pushvalue(L, -3); /* the http context table */ + + /* + * make luci_parse_header a closure + * argument 1: the luci.vars table + * argument 2: the http context table + */ + lua_pushcclosure(L, luci_parse_header, 2); + ret = luci_pcall(L, "parse_header", 0); + + lua_getfield(L, -1, "handle_req"); + ret = lua_isfunction(L, -1); + if (!ret) + goto done; + + lua_pushvalue(L, -3); + ret = luci_pcall(L, "handle_req", 1); + + /* pop the luci and http context tables */ +done: + lua_pop(L, 2); + return ret; +} + +static void luci_unload(struct httpd_plugin *p) +{ + lua_close(L); +} + +HTTPD_PLUGIN { + .prefix = "/luci/", + .init = luci_init, + .done = luci_unload, + .prepare_req = luci_prepare_req, + .handle_req = luci_handle_req, +}; diff --git a/libs/web/root/etc/config/luci b/libs/web/root/etc/config/luci index 87170a9b1..701c93938 100644 --- a/libs/web/root/etc/config/luci +++ b/libs/web/root/etc/config/luci @@ -1,7 +1,7 @@ config core main option lang de - option mediaurlbase /luci/fledermaus - option resourcebase /luci/resources + option mediaurlbase /luci-static/fledermaus + option resourcebase /luci-static/resources config core brand option title "OpenWRT Kamikaze" @@ -36,4 +36,4 @@ config internal languages option en "English" config internal themes - option Fledermaus "/luci/fledermaus" + option Fledermaus "/luci-static/fledermaus" diff --git a/themes/fledermaus/root/www/luci/fledermaus/cascade.css b/themes/fledermaus/root/www/luci-static/fledermaus/cascade.css similarity index 100% rename from themes/fledermaus/root/www/luci/fledermaus/cascade.css rename to themes/fledermaus/root/www/luci-static/fledermaus/cascade.css diff --git a/themes/fledermaus/root/www/luci/fledermaus/logo.png b/themes/fledermaus/root/www/luci-static/fledermaus/logo.png similarity index 100% rename from themes/fledermaus/root/www/luci/fledermaus/logo.png rename to themes/fledermaus/root/www/luci-static/fledermaus/logo.png -- 2.11.0