diff options
author | Christian Pointner <equinox@spreadspace.org> | 2010-10-02 00:00:32 +0000 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2010-10-02 00:00:32 +0000 |
commit | 621c7f4acf2ce36db5dcae2de1d013f7de2f2cf8 (patch) | |
tree | d51cc5299a535929923fb45edd88ac5731b7e66e /src/gcsd.c | |
parent | added initial svn dirs (diff) |
inital checkin (base daemon should be running)
git-svn-id: https://svn.spreadspace.org/gcsd/trunk@2 ac14a137-c7f1-4531-abe0-07747231d213
Diffstat (limited to 'src/gcsd.c')
-rw-r--r-- | src/gcsd.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/src/gcsd.c b/src/gcsd.c new file mode 100644 index 0000000..76a9fc3 --- /dev/null +++ b/src/gcsd.c @@ -0,0 +1,257 @@ +/* + * gcsd + * + * gcsd the generic command sequencer daemon can be used to serialize + * commands sent over various paralell communication channels to a + * single command output. It can be seen as a multiplexer for any + * kind of communication between a single resource and various clients + * which want to submit commands to it or query information from it. + * gcsd is written in C and Lua. The goal is to provide an easy to + * understand high level API based on Lua which can be used to + * implement the business logic of the so formed multiplexer daemon. + * + * + * Copyright (C) 2009-2010 Markus Grueneis <gimpf@spreadspace.org> + * Christian Pointner <equinox@spreadspace.org> + * + * This file is part of gcsd. + * + * gcsd 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 + * any later version. + * + * gcsd 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 gcsd. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +#include "datatypes.h" +#include "options.h" +#include "string_list.h" +#include "log.h" +#include "l_log.h" +#include "l_sig_handler.h" + +#ifndef WINVER +#include "daemon.h" +#endif + +extern const uint8_t gcsd_lua_bytecode[]; +extern const uint32_t gcsd_lua_bytecode_len; + +#define LUA_MAIN_LOOP_FUNC "main_loop" + +static const luaL_Reg gcsd_lualibs[] = { + {"", luaopen_base}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_LOGLIBNAME, luaopen_log}, + {LUA_SIGNALLIBNAME, luaopen_signal}, + {NULL, NULL} +}; + +int init_main_loop(lua_State *L) +{ + const luaL_Reg *lib = gcsd_lualibs; + for (; lib->func; lib++) { + lua_pushcfunction(L, lib->func); + lua_pushstring(L, lib->name); + lua_call(L, 1, 0); + } + + int ret = luaL_loadbuffer(L, gcsd_lua_bytecode, gcsd_lua_bytecode_len, "gcsd"); + if(ret) { + const char* err_str = luaL_checkstring(L, -1); + switch(ret) { + case LUA_ERRSYNTAX: log_printf(ERROR, "luaL_loadbuffer() syntax error: %s", err_str); break; + case LUA_ERRMEM: log_printf(ERROR, "luaL_loadbuffer() malloc error: %s", err_str); break; + default: log_printf(ERROR, "luaL_loadbuffer() unknown error: %s", err_str); break; + } + return -1; + } + + ret = lua_pcall(L, 0, 0, 0); + if(ret) { + const char* err_str = luaL_checkstring(L, -1); + switch(ret) { + case LUA_ERRRUN: log_printf(ERROR, "lua_pcall() runtime error: %s", err_str); break; + case LUA_ERRMEM: log_printf(ERROR, "lua_pcall() malloc error: %s", err_str); break; + case LUA_ERRERR: log_printf(ERROR, "lua_pcall() error at error handler function: %s", err_str); break; + } + return -1; + } + + return 0; +} + +int call_main_loop(lua_State* L, options_t* opt) +{ + lua_getglobal(L, LUA_MAIN_LOOP_FUNC); + if(!lua_isfunction(L, -1)) { + log_printf(ERROR, "there is no function '%s' inside gcsd bytecode", LUA_MAIN_LOOP_FUNC); + return -1; + }; + + options_lua_push(opt, L); + + int ret = lua_pcall(L, 1, LUA_MULTRET, 0); + if(ret) { + const char* err_str = luaL_checkstring(L, -1); + switch(ret) { + case LUA_ERRRUN: log_printf(ERROR, "lua_pcall(%s) runtime error: %s", LUA_MAIN_LOOP_FUNC, err_str); break; + case LUA_ERRMEM: log_printf(ERROR, "lua_pcall(%s) malloc error: %s", LUA_MAIN_LOOP_FUNC, err_str); break; + case LUA_ERRERR: log_printf(ERROR, "lua_pcall(%s) error at error handler function: %s", LUA_MAIN_LOOP_FUNC, err_str); break; + } + return -1; + } + + int n = lua_gettop(L); + log_printf(DEBUG, "%s returned %d values", LUA_MAIN_LOOP_FUNC, n); + int i; + for (i = 1; i <= n; i++) + log_printf(DEBUG, "return value [%d] = '%s'", i, luaL_checkstring(L, i)); + + ret = lua_tointeger(L, 1); + return ret; +} + +int main_loop(options_t* opt) +{ + lua_State *L; + L = luaL_newstate(); + if(!L) { + log_printf(ERROR, "error creating lua state"); + return -1; + } + + int ret = init_main_loop(L); + if(!ret) + ret = call_main_loop(L, opt); + + lua_close(L); + return ret; +} + +int main(int argc, char* argv[]) +{ + log_init(); + + options_t opt; + int ret = options_parse(&opt, argc, argv); + if(ret) { + if(ret > 0) { + fprintf(stderr, "syntax error near: %s\n\n", argv[ret]); + } + if(ret == -2) { + fprintf(stderr, "memory error on options_parse, exitting\n"); + } + if(ret == -3) { + options_print_version(); + } + + if(ret != -2 && ret != -3) + options_print_usage(); + + if(ret == -1 || ret == -3) + ret = 0; + + options_clear(&opt); + log_close(); + exit(ret); + } + string_list_element_t* tmp = opt.log_targets_.first_; + while(tmp) { + ret = log_add_target(tmp->string_); + if(ret) { + switch(ret) { + case -2: fprintf(stderr, "memory error on log_add_target, exitting\n"); break; + case -3: fprintf(stderr, "unknown log target: '%s', exitting\n", tmp->string_); break; + case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", tmp->string_); break; + default: fprintf(stderr, "syntax error near: '%s', exitting\n", tmp->string_); break; + } + + options_clear(&opt); + log_close(); + exit(ret); + } + tmp = tmp->next_; + } + + log_printf(NOTICE, "just started..."); + options_parse_post(&opt); + +#ifndef WINVER + priv_info_t priv; + if(opt.username_) + if(priv_init(&priv, opt.username_, opt.groupname_)) { + options_clear(&opt); + log_close(); + exit(-1); + } +#endif + +#ifndef WINVER + FILE* pid_file = NULL; + if(opt.pid_file_) { + pid_file = fopen(opt.pid_file_, "w"); + if(!pid_file) { + log_printf(WARNING, "unable to open pid file: %s", strerror(errno)); + } + } + + if(opt.chroot_dir_) + if(do_chroot(opt.chroot_dir_)) { + options_clear(&opt); + log_close(); + exit(-1); + } + if(opt.username_) + if(priv_drop(&priv)) { + options_clear(&opt); + log_close(); + exit(-1); + } + + if(opt.daemonize_) { + pid_t oldpid = getpid(); + daemonize(); + log_printf(INFO, "running in background now (old pid: %d)", oldpid); + } + + if(pid_file) { + pid_t pid = getpid(); + fprintf(pid_file, "%d", pid); + fclose(pid_file); + } +#endif + + ret = main_loop(&opt); + + options_clear(&opt); + + if(!ret) + log_printf(NOTICE, "normal shutdown"); + else if(ret < 0) + log_printf(NOTICE, "shutdown after error"); + else + log_printf(NOTICE, "shutdown after signal"); + + log_close(); + + return ret; +} |