diff --git a/mote/v2/openwrt/package/flukso/Makefile b/mote/v2/openwrt/package/flukso/Makefile index de7f9d9..2b9b99e 100644 --- a/mote/v2/openwrt/package/flukso/Makefile +++ b/mote/v2/openwrt/package/flukso/Makefile @@ -1,5 +1,4 @@ -# Copyright (c) 2010 flukso.net -# $Id$ +# Copyright (c) 2010-2011 Bart Van Der Meerssche include $(TOPDIR)/rules.mk @@ -14,7 +13,7 @@ include $(INCLUDE_DIR)/package.mk define Package/flukso SECTION:=utils CATEGORY:=Utilities - DEPENDS:=+ntpclient +nixio +rrdtool1 + DEPENDS:=+libdaemon +ntpclient +liblua +luci-nixio +rrdtool1 TITLE:=Flukso - community metering endef @@ -24,18 +23,19 @@ endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ $(CP) ./luasrc/* $(PKG_BUILD_DIR)/ endef - -define Build/Compile -endef - define Package/flukso/install $(INSTALL_DIR) $(1)/usr/lib/lua - $(CP) $(PKG_BUILD_DIR)/dbg.lua $(1)/usr/lib/lua/ + $(INSTALL_DATA) $(PKG_BUILD_DIR)/dbg.lua $(1)/usr/lib/lua/ $(INSTALL_DIR) $(1)/usr/lib/lua/rrd - $(CP) $(PKG_BUILD_DIR)/rrd/*.lua $(1)/usr/lib/lua/rrd/ + $(INSTALL_DATA) $(PKG_BUILD_DIR)/rrd/*.lua $(1)/usr/lib/lua/rrd/ + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/luad $(1)/usr/sbin/ + $(LN) /usr/sbin/luad $(1)/usr/sbin/spid + $(INSTALL_BIN) $(PKG_BUILD_DIR)/spi/spid.lua $(1)/usr/sbin/ endef $(eval $(call BuildPackage,flukso)) diff --git a/mote/v2/openwrt/package/flukso/luasrc/spi/spid.lua b/mote/v2/openwrt/package/flukso/luasrc/spi/spid.lua new file mode 100755 index 0000000..c8cd696 --- /dev/null +++ b/mote/v2/openwrt/package/flukso/luasrc/spi/spid.lua @@ -0,0 +1,60 @@ +#! /usr/bin/env lua + +--[[ + + spid.lua - Lua part of the spi daemon + + Copyright (C) 2011 Bart Van Der Meerssche + + 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 3 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, see . + +]]-- + + +require 'nixio.fs' + +ctrl_path = os.getenv('DAEMON_PATH') .. '/ctrl/' + +nixio.fs.mkdirr(ctrl_path) +nixio.fs.unlink(ctrl_path .. 'in') +nixio.fs.unlink(ctrl_path .. 'out') + +nixio.fs.mkfifo(ctrl_path .. 'in', '644') +nixio.fs.mkfifo(ctrl_path .. 'out', '644') + +rdwr_nonblock = nixio.open_flags('rdwr', 'nonblock') + +ctrl_fd_in = nixio.open(ctrl_path .. 'in', rdwr_nonblock) +ctrl_fd_out = nixio.open(ctrl_path .. 'out', rdwr_nonblock) + +pfin = nixio.poll_flags('in') + +local fd = {fd = ctrl_fd_in, + events = pfin, + revents = 0} + +local fds = {fd} + +ctrl_line = ctrl_fd_in:linesource() + +while true do + if nixio.poll(fds, 1000) then + ctrl_fd_out:write((ctrl_line() or 'nil!') .. '\n') + else + ctrl_fd_out:write('timeout\n') + end +end + +nixio.fs.unlink(ctrl_path .. 'in') +nixio.fs.unlink(ctrl_path .. 'out') diff --git a/mote/v2/openwrt/package/flukso/src/luad.c b/mote/v2/openwrt/package/flukso/src/luad.c new file mode 100644 index 0000000..a7effd2 --- /dev/null +++ b/mote/v2/openwrt/package/flukso/src/luad.c @@ -0,0 +1,317 @@ +/* + + luad.c - A libdaemon-based generic daemonization framework for Lua code. + + Copyright (C) 2003-2008 Lennart Poettering + 2011 Bart Van Der Meerssche + + 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 3 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, see . + +*/ + + +/* Enable GNU extensions so we can use asprintf */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef OPENWRT_BUILD +#define DAEMON_USER "flukso" +#define DAEMON_GROUP "flukso" +#else +#define DAEMON_USER "icarus75" +#define DAEMON_GROUP "icarus75" +#endif + +#define DAEMON_VARRUN "/var/run" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef OPENWRT_BUILD +#include +#include +#include +#else +#include +#include +#include +#endif + +static void sigterm(int signo) +{ + daemon_log(LOG_INFO, "Caught a SIGTERM. Exiting... "); + daemon_pid_file_remove(); + exit(0); +} + +static const char *daemon_pid_file_proc_override(void) +{ + char *fn; + + asprintf(&fn, "%s/%s/pid", DAEMON_VARRUN, daemon_log_ident); + return fn; +} + +static int drop_root(void) +{ + struct passwd *pw; + struct group * gr; + + if (!(pw = getpwnam(DAEMON_USER))) { + daemon_log(LOG_ERR, "Failed to find user '"DAEMON_USER"'"); + return -1; + } + + if (!(gr = getgrnam(DAEMON_GROUP))) { + daemon_log(LOG_ERR, "Failed to find group '"DAEMON_GROUP"'"); + return -1; + } + + if (initgroups(DAEMON_USER, gr->gr_gid) != 0) { + daemon_log(LOG_ERR, "Failed to change group list: %s", strerror(errno)); + return -1; + } + + if (setregid(gr->gr_gid, gr->gr_gid) < 0) { + daemon_log(LOG_ERR, "Failed to change GID: %s", strerror(errno)); + return -1; + } + + if (setreuid(pw->pw_uid, pw->pw_uid) < 0) { + daemon_log(LOG_ERR, "Failed to change UID: %s", strerror(errno)); + return -1; + } + + setenv("USER", pw->pw_name, 1); + setenv("LOGNAME", pw->pw_name, 1); + setenv("HOME", pw->pw_dir, 1); + + return 0; +} + +static int make_runtime_dir(char **pruntime_path) +{ + int r = -1; + mode_t u; + int reset_umask = 0; + + struct passwd *pw; + struct group * gr; + struct stat st; + + asprintf(pruntime_path, "%s/%s", DAEMON_VARRUN, daemon_log_ident); + + if (!(pw = getpwnam(DAEMON_USER))) { + daemon_log(LOG_ERR, "Failed to find user '"DAEMON_USER"'"); + goto fail; + } + + if (!(gr = getgrnam(DAEMON_GROUP))) { + daemon_log(LOG_ERR, "Failed to find group '"DAEMON_GROUP"'"); + goto fail; + } + + u = umask(0000); + reset_umask = 1; + + if (mkdir(*pruntime_path, 0755) < 0 && errno != EEXIST) { + daemon_log(LOG_ERR, "mkdir(\"%s\"): %s", *pruntime_path, strerror(errno)); + goto fail; + } + + chown(*pruntime_path, pw->pw_uid, gr->gr_gid); + + if (stat(*pruntime_path, &st) < 0) { + daemon_log(LOG_ERR, "stat(\"%s\"): %s\n", *pruntime_path, strerror(errno)); + goto fail; + } + + if (!S_ISDIR(st.st_mode) || st.st_uid != pw->pw_uid || st.st_gid != gr->gr_gid) { + daemon_log(LOG_ERR, "Failed to create runtime directory \"%s\"", *pruntime_path); + goto fail; + } + + r = 0; + +fail: + if (reset_umask) + umask(u); + return r; +} + +int main(int argc, char *argv[]) +{ + pid_t pid; + struct sigaction sa; + + lua_State *L = NULL; + char *luad_path = NULL; + char *runtime_path = NULL; + + /* Reset signal handlers */ + if (daemon_reset_sigs(-1) < 0) { + daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno)); + return 1; + } + + /* Unblock signals */ + if (daemon_unblock_sigs(-1) < 0) { + daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno)); + return 1; + } + + /* Set the daemon's syslog identification string */ + daemon_log_ident = daemon_ident_from_argv0(argv[0]); + + /* Set the pid file to /var/run// */ + daemon_pid_file_proc = daemon_pid_file_proc_override; + + /* Check if we are called with -k parameter */ + if (argc >= 2 && !strcmp(argv[1], "-k")) { + int ret; + + /* Kill daemon with SIGTERM */ + + /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */ + if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0) { + daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno)); + } + + return ret < 0 ? 1 : 0; + } + + + if (getuid() != 0) { + daemon_log(LOG_ERR, "This daemon should be run as root."); + return 1; + } + + /* Check that the daemon is not run twice a the same time */ + if ((pid = daemon_pid_file_is_running()) >= 0) { + daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid); + return 1; + } + + /* Prepare for return value passing from the initialization procedure of the daemon process */ + if (daemon_retval_init() < 0) { + daemon_log(LOG_ERR, "Failed to create pipe."); + return 1; + } + + /* Do the fork */ + if ((pid = daemon_fork()) < 0) { + + /* Exit on error */ + daemon_retval_done(); + return 1; + } + else if (pid) { /* The parent */ + int ret; + + /* Wait for 20 seconds for the return value passed from the daemon process */ + if ((ret = daemon_retval_wait(20)) < 0) { + daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno)); + return 255; + } + + daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret); + return ret; + } + else { /* The daemon */ + /* Close FDs */ + if (daemon_close_all(-1) < 0) { + daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno)); + + /* Send the error condition to the parent process */ + daemon_retval_send(1); + goto finish; + } + + /* Create the daemon runtime dir */ + if (make_runtime_dir(&runtime_path) < 0) { + goto finish; + } + + /* Drop root priviledges */ + if (drop_root() < 0) { + daemon_log(LOG_ERR, "Could not drop root privileges for %s/%s", DAEMON_USER, DAEMON_GROUP); + goto finish; + } + + /* Create the PID file */ + if (daemon_pid_file_create() < 0) { + daemon_log(LOG_ERR, "Could not create PID file (%s)", strerror(errno)); + daemon_retval_send(2); + goto finish; + } + + /* Initialize signal handling */ + sa.sa_handler = sigterm; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGTERM); + sa.sa_flags = 0; + + if(sigaction(SIGTERM, &sa, NULL) < 0) { + daemon_log(LOG_ERR, "Cannot catch SIGTERM: %s", strerror(errno)); + daemon_retval_send(3); + goto finish; + } + + /* Set environment vars for the Lua daemon */ + setenv("DAEMON", daemon_log_ident, 1); + setenv("DAEMON_PATH", runtime_path, 1); + + /* Send OK to parent process */ + daemon_retval_send(0); + daemon_log(LOG_INFO, "Sucessfully started with DEAMON=%s and DAEMON_PATH=%s", daemon_log_ident, runtime_path); + + /* Create a new Lua environment */ + L = luaL_newstate(); + /* And load the standard libraries into the Lua environment */ + luaL_openlibs(L); + /* Derive the Lua daemon path from the C daemon one */ + asprintf(&luad_path, "%s%s", (const char *)argv[0], ".lua"); + /* Tunnel through the wormhole into Lua neverland. This call should never return. */ + if (luaL_dofile(L, (const char *)luad_path)) { + daemon_log(LOG_ERR, "Lua returned with error message: %s", lua_tostring(L,-1)); + } + /* Clean up the Lua state */ + lua_close(L); + + + /* Do a cleanup */ +finish: + daemon_log(LOG_INFO, "Exiting..."); + daemon_retval_send(255); + daemon_pid_file_remove(); + + return 0; + } +} diff --git a/mote/v2/openwrt/package/flukso/src/makefile b/mote/v2/openwrt/package/flukso/src/makefile new file mode 100644 index 0000000..fdd2577 --- /dev/null +++ b/mote/v2/openwrt/package/flukso/src/makefile @@ -0,0 +1,25 @@ +# Copyright (c) 2011 Bart Van Der Meerssche + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu89 + +all: luad.o +ifeq ($(OPENWRT_BUILD),1) + $(CC) $(LDFLAGS) $(CSTANDARD) -ldl -lm -lcrypt -ldaemon -llua luad.o -o luad +else + $(CC) $(LDFLAGS) $(CSTANDARD) -ldl -lm -lcrypt -ldaemon -llua5.1 luad.o -o luad +endif + +luad.o: luad.c +ifeq ($(OPENWRT_BUILD),1) + $(CC) $(CFLAGS) $(CSTANDARD) -Wall -D OPENWRT_BUILD=1 -c luad.c +else + $(CC) $(CFLAGS) $(CSTANDARD) -Wall -c luad.c +endif + +clean: + rm *.o luad