Lua fork concurrent processes - lua

I want to execute background processes concurrently from a lua script
like :
a = io.popen("deploy.exp" .. ip1):read("*a")
b = io.popen("deploy.exp" .. ip2):read("*a")
where a,b are continually running processes. When i do this as above, b will only run when a is finished. And the deploy.exp script is an expect script which used to ssh few servers, and execute some commands. Then I need to fetch some text from a and b. Any idea on this? I tryed with the ExtensionProposal API. When I tried that I get one error messages that say: "* glibc detected free(): invalid next size (fast): 0x08aa2300 ** abort".
The part code is
for k,v in pairs(single) do
command = k .. " 1 " .. table.concat(v, " ")
local out = io.pipe()
local pro = assert(os.spawn("./spaw.exp " .. command,{
stdout = out,
}))
if not proc then error("Failed to aprogrinate! "..tostring(err)) end
print(string.rep("#", 50))
local exitcode = proc:wait()
end
Has anybody any experience (or advice / where we should look) with this? or give me a sample? Thanks
BTW: I tried the luaposix, but I can't find any sample by posix.fork(). Does anyone could share one? TKS

posix.fork() is part of the luaposix library, which can be installed via luarocks. It works in much the same way as fork(3); it creates an copy of the parent process, and both of them will execute everything after the call to fork(). The return value of fork() is 0 in the child process, otherwise it's the PID of the child that was just spawned. Here's a contrived example:
local posix = require "posix"
local pid = posix.fork()
if pid == 0 then
-- this is the child process
print(posix.getpid('pid') .. ": child process")
else
-- this is the parent process
print(posix.getpid('pid') .. ": parent process")
-- wait for the child process to finish
posix.wait(pid)
end
-- both processes get here
print(posix.getpid('pid') .. ": quitting")
This should output something like the following:
$ lua fork.lua
27219: parent process
27220: child process
27220: quitting
27219: quitting

You might want to try Lua Lanes (or from here), which is a portable threading library for Lua.

Related

Lua io.popen freezing after a while of reading a log file

I'm attempting to constantly read and parse a log file (Minecraft log file) by using io.popen in tandem with Ubuntu's tail command so that I can send some messages upon certain events.
Now, I have mostly everything working here, except one small issue. After a while of reading, the entire program just freezes.
Here is the relevant code:
-- Open the tail command, return a file handle for it.
local pop = io.popen(config.listen_command)
-- Simply read a single line, I've pulled this into its own
-- function so that if this ever needs changing I can do so
-- easily.
local function get_line()
logger:log(4, "READ LINE")
return pop:read("*l")
end
-- For each line in the log file, check if it matches any
-- of a list of patterns, return the matches and the
-- pattern information if so.
local function match_line()
local line = get_line()
logger:log(4, "Line: %s", line)
-- This all works, and I've tested that it's not freezing
-- here. I've just included it for completion of the call
-- -stack.
for event_type, data in pairs(config.message_patterns) do
for event_name, pattern in pairs(data) do
local matches = {line:match(pattern)}
if matches[1] then
return event_type, event_name, matches
end
end
end
end
-- The main loop, simply read a line and send a message
-- if there was a match.
logger:log(4, "Main loop begin.")
while true do
local event_type, event_name, matches = match_line()
-- ...
-- The rest of the code here is not relevant.
config.listen_command = "tail -F --lines=1 latest.log"
The issue is in the get_line function. After a while of reading the log file, it completely freezes on the pop:read("*l"). It prints the READ LINE message, but never prints the Line: <whatever data here> line.
This is a really strange issue that I've been getting really confused about. I've tried swapping to different distributions of Lua (Luvit, LuaJIT, Lua) and a very large amount of debugging, changing small things, rerunning, ... But I cannot think of anything that'd be causing this.
Perhaps there's something small I've missed.
So my question here is this: Why is pop:read("*l") freezing, even though more data is being outputted to the logfile? Is there a way to fix this? Perhaps to detect if the next read will freeze indefinitely, so I can try closing the popen'ed file and re-open it (or to preferably stop it happening altogether?)

Detect change in lua stdin/stdout

I have a lua script which is started by an external process - the two then interact through StandardInput and StandardOutput, through a simple loop:
local running = true;
while running do
print('ready'); io.flush(); --the parent process now knows it can interact with the lua script
local input = io.read(); --the parent process, whenever ready, provides the lua script with a given input
if input=="exit" then running=false --this ends the script...
else print(DoStuffWithInput(input)); --...or the lua script responds here
end
I want the lua script to end if it detects that the parent process no longer exists, given that currently CPU usage jumps to 100% when the parent is closed (presumably because io.read() is no longer needing to wait for any input, although I'm not sure what it's reading instead).
What would be an elegant and safe way of detecting if the parent process has closed (presumably changing the stdin and stdout of the lua script)?
I've tried a few things, but io.stdin and io.stdout always seem to be a file, and I'm not sure where to go from here.

How can I kill a child process using LUA?

I'm trying to kill a process using Lua: my bash script "run.sh" prints a string each 2 seconds and up to now I was able to catch real-time the output but I need to quit that process too whenever i send a command to my telegram bot
Here is my actual code:
local bot, extension = require("lua-bot-api").configure('myBotToken')
local function test()
local pipe = io.popen'/home/ubuntu/workspace/LmBot/run.sh'
repeat
local c = pipe:read("*line")
if c then
io.write(c)
io.flush()
bot.sendMessage(msg.from.id,c,"Markdown")
end
until not c
pipe:close()
end
extension.onTextReceive = function(msg)
local matches = {msg.text:match('^/(.+)$')}
if(matches[1]=='start')then
test()
end
end
extension.run()
As you can see, when I send command /start it runs my bash script (is that a child process? am I right?) and sends me back a message with the output parsed by lines in real time.
I now need to be able to kill the process started before, are there any ways using lua?
Thank you all in advance :)

Getting return status AND program output

I need to use Lua to run a binary program that may write something in its stdout and also returns a status code (also known as "exit status").
I searched the web and couldn't find something that does what I need. However I found out that in Lua:
os.execute() returns the status code
io.popen() returns a file handler that can be used to read process output
However I need both. Writing a wrapper function that runs both functions behind the scene is not an option because of process overhead and possibly changes in result on consecutive runs. I need to write a function like this:
function run(binpath)
...
return output,exitcode
end
Does anyone has an idea how this problem can be solved?
PS. the target system rung Linux.
With Lua 5.2 I can do the following and it works
-- This will open the file
local file = io.popen('dmesg')
-- This will read all of the output, as always
local output = file:read('*all')
-- This will get a table with some return stuff
-- rc[1] will be true, false or nil
-- rc[3] will be the signal
local rc = {file:close()}
I hope this helps!
I can't use Lua 5.2, I use this helper function.
function execute_command(command)
local tmpfile = '/tmp/lua_execute_tmp_file'
local exit = os.execute(command .. ' > ' .. tmpfile .. ' 2> ' .. tmpfile .. '.err')
local stdout_file = io.open(tmpfile)
local stdout = stdout_file:read("*all")
local stderr_file = io.open(tmpfile .. '.err')
local stderr = stderr_file:read("*all")
stdout_file:close()
stderr_file:close()
return exit, stdout, stderr
end
This is how I do it.
local process = io.popen('command; echo $?') -- echo return code of last run command
local lastline
for line in process:lines() do
lastline = line
end
print(lastline) -- the return code is the last line of output
If the last line has fixed length you can read it directly using file:seek("end", -offset), offset should be the length of the last line in bytes.
This functionality is provided in C by pclose.
Upon successful return, pclose() shall return the termination status
of the command language interpreter.
The interpreter returns the termination status of its child.
But Lua doesn't do this right (io.close always returns true). I haven't dug into these threads but some people are complaining about this brain damage.
http://lua-users.org/lists/lua-l/2004-05/msg00005.html
http://lua-users.org/lists/lua-l/2011-02/msg00387.html
If you're running this code on Win32 or in a POSIX environment, you could try this Lua extension: http://code.google.com/p/lua-ex-api/
Alternatively, you could write a small shell script (assuming bash or similar is available) that:
executes the correct executable, capturing the exit code into a shell variable,
prints a newline and terminal character/string onto standard out
prints the shell variables value (the exit code) onto standard out
Then, capture all the output of io.popen and parse backward.
Full disclosure: I'm not a Lua developer.
yes , your are right that os.execute() has returns and it's very simple if you understand how to run your command with and with out lua
you also may want to know how many variables it returns , and it might take a while , but i think you can try
local a, b, c, d, e=os.execute(-what ever your command is-)
for my example a is an first returned argument , b is the second returned argument , and etc.. i think i answered your question right, based off of what you are asking.

Reboot a System through Lua Script

I need to reboot System through a Lua Script.
I need to write some string before the Reboot happens and need to write a string in a Lua
script once the Reboot is done.
Example :
print("Before Reboot System")
Reboot the System through Lua script
print("After Reboot System")
How would I accomplish this?
You can use os.execute to issue system commands. For Windows, it's shutdown -r, for Posix systems it's just reboot. Your Lua code will therefore look like this:
Be aware that part of the reboot command is stopping active programs, like your Lua script. That means that any data stored in RAM will be lost. You need to write any data you want to keep to disk, using, for instance, table serialization.
Unfortunately, without more knowledge of your environment, I can't tell you how to call the script again. You could be able to append a call to your script to the end of ~/.bashrc or similar.
Make sure that loading this data and starting at a point after you call your reboot function is the first thing that you do when you come back! You don't want to get stuck in an endless reboot loop where the first thing your computer does when it turns on is to turn itself off. Something like this should work:
local function is_rebooted()
-- Presence of file indicates reboot status
if io.open("Rebooted.txt", "r") then
os.remove("Rebooted.txt")
return true
else
return false
end
end
local function reboot_system()
local f = assert(io.open("Rebooted.txt", "w"))
f:write("Restarted! Call On_Reboot()")
-- Do something to make sure the script is called upon reboot here
-- First line of package.config is directory separator
-- Assume that '\' means it's Windows
local is_windows = string.find(_G.package.config:sub(1,1), "\\")
if is_windows then
os.execute("shutdown -r");
else
os.execute("reboot")
end
end
local function before_reboot()
print("Before Reboot System")
reboot_system()
end
local function after_reboot()
print("After Reboot System")
end
-- Execution begins here !
if not is_rebooted() then
before_reboot()
else
after_reboot()
end
(Warning - untested code. I didn't feel like rebooting. :)
There is no way to do what you are asking in Lua. You may be able to do this using os.execute depending on your system and set up but Lua's libraries only include what is possible in the standard c libraries which does not include operating system specific functionality like restart.

Resources