diff options
author | Christian Pointner <equinox@spreadspace.org> | 2010-11-22 19:06:30 +0000 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2010-11-22 19:06:30 +0000 |
commit | 8fd3021706d48a8cdf4993f203a3cdabeb385544 (patch) | |
tree | b8b84a220fbf6cb00d17d4b5a8a3771a14dcad47 | |
parent | cleanup (diff) |
added initial exec module
git-svn-id: https://svn.spreadspace.org/gcsd/trunk@52 ac14a137-c7f1-4531-abe0-07747231d213
-rw-r--r-- | src/modules/exec.lua | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/modules/exec.lua b/src/modules/exec.lua new file mode 100644 index 0000000..b819b6f --- /dev/null +++ b/src/modules/exec.lua @@ -0,0 +1,155 @@ +-- +-- 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/>. +-- + +local defines = require("defines") + +-- exec module class +local exec = {} +exec.properties = { type=defines.INOUT_MODULE, name="exec", max_instances=-1 } +exec.defaults = { script = "exec.sh" } + +-- create new instance of exec module class +function exec:new(config) + local inst = {} + inst.class = self.properties.name + inst.config = config + if(config.name == nil or config.name == "") then + inst.name = self.properties.name + else + inst.name = config.name + end + if(not config.script) then config.script = self.defaults.script end + + local reader, writer_child = util.pipe() + if(reader == nil) then + log.printf(log.ERROR, inst.name .. ": pipe failed: %s", writer_child) + return nil + end + local reader_child, writer = util.pipe() + if(writer == nil) then + log.printf(log.ERROR, inst.name .. ": pipe failed: %s", reader_child) + return nil + end + local pid, err = util.exec(config.script, nil, nil, reader_child, writer_child) + if(pid == nil) then + log.printf(log.ERROR, inst.name .. ": exec failed: %s", error) + return nil + end + + log.printf(log.NOTICE, inst.name .. ": child spawned with pid %d", pid) + + local in_handle = {} + in_handle.fd = reader + rawio.setnonblock(in_handle.fd) + in_handle.client_instance = nil + in_handle.in_buffer = "" + function in_handle:getfd() return self.fd end + function in_handle:read() + -- TODO: which size should we request?? + local buffer, err = rawio.read(self.fd, 100) + if(buffer == nil) then + log.printf(log.ERROR, inst.name .. ": connection error: %s", err) + return defines.KILL_MODULE_CLASS + end + + -- TODO: support read until matched command + self.in_buffer = self.in_buffer .. buffer + -- TODO: dispatch table et al + command_queue:command_completed() + + return defines.OK + end + function in_handle:write() end + + local out_handle = {} + out_handle.fd = writer + rawio.setnonblock(out_handle.fd) + out_handle.client_instance = nil + out_handle.out_buffer = "" + function out_handle:getfd() return self.fd end + function out_handle:read() end + function out_handle:write() + local len, err = rawio.write(self.fd, self.out_buffer) + if(len == nil) then + log.printf(log.ERROR, inst.name .. ": connection error: %s", err) + ret = defines.KILL_MODULE_CLASS + else + self.out_buffer = string.sub(self.out_buffer, len+1) + end + if(self.out_buffer == "") then + command_queue:command_sent() + end + return defines.OK + end + + local client = {} + client.module_instance = inst + client.name = inst.name .. "#0" + client.pid = pid + function client:process_response() end + function client:process_timeout() end + function client:get_read_handles() + return { in_handle } + end + function client:get_write_handles() + if(out_handle.out_buffer ~= "") then + return { out_handle } + else + return {} + end + end + function client:cleanup() + -- TODO: kill child + end + in_handle.client_instance = client + out_handle.client_instance = client + + function inst:cleanup() + client_list:unregister_by_module(self) + end + function inst:get_read_handles() + return {} + end + function inst:get_write_handles() + return {} + end + function inst:start_command(command) + out_handle.out_buffer = command + end + setmetatable(inst, {}) + getmetatable(inst).__gc = function() inst:cleanup() end + + client_list:register(client) + return inst +end + +return exec |