mirror of
https://github.com/zeek/zeek.git
synced 2025-10-11 11:08:20 +00:00
allow sending data to stdin of child process
This commit is contained in:
parent
fc42c71dfa
commit
3aeec7ec14
5 changed files with 166 additions and 24 deletions
|
@ -19,6 +19,7 @@ using threading::Field;
|
||||||
|
|
||||||
const int Raw::block_size = 512; // how big do we expect our chunks of data to be...
|
const int Raw::block_size = 512; // how big do we expect our chunks of data to be...
|
||||||
|
|
||||||
|
|
||||||
Raw::Raw(ReaderFrontend *frontend) : ReaderBackend(frontend)
|
Raw::Raw(ReaderFrontend *frontend) : ReaderBackend(frontend)
|
||||||
{
|
{
|
||||||
file = 0;
|
file = 0;
|
||||||
|
@ -41,6 +42,8 @@ Raw::Raw(ReaderFrontend *frontend) : ReaderBackend(frontend)
|
||||||
assert(stderr_fileno == 2);
|
assert(stderr_fileno == 2);
|
||||||
|
|
||||||
childpid = -1;
|
childpid = -1;
|
||||||
|
|
||||||
|
stdin_towrite = 0; // by default do not open stdin
|
||||||
}
|
}
|
||||||
|
|
||||||
Raw::~Raw()
|
Raw::~Raw()
|
||||||
|
@ -53,6 +56,7 @@ void Raw::DoClose()
|
||||||
if ( file != 0 )
|
if ( file != 0 )
|
||||||
CloseInput();
|
CloseInput();
|
||||||
|
|
||||||
|
|
||||||
if ( execute && childpid > 0 )
|
if ( execute && childpid > 0 )
|
||||||
// kill child process
|
// kill child process
|
||||||
kill(childpid, 9); // TERMINATOR
|
kill(childpid, 9); // TERMINATOR
|
||||||
|
@ -60,9 +64,8 @@ void Raw::DoClose()
|
||||||
|
|
||||||
bool Raw::Execute()
|
bool Raw::Execute()
|
||||||
{
|
{
|
||||||
int stdout_pipe[2];
|
|
||||||
|
|
||||||
if (pipe(stdout_pipe) != 0)
|
if (pipe(pipes) != 0 || pipe(pipes+2) || pipe(pipes+4) )
|
||||||
{
|
{
|
||||||
Error(Fmt("Could not open pipe: %d", errno));
|
Error(Fmt("Could not open pipe: %d", errno));
|
||||||
return false;
|
return false;
|
||||||
|
@ -77,8 +80,15 @@ bool Raw::Execute()
|
||||||
else if ( childpid == 0 )
|
else if ( childpid == 0 )
|
||||||
{
|
{
|
||||||
// we are the child.
|
// we are the child.
|
||||||
close(stdout_pipe[stdin_fileno]);
|
close(pipes[stdout_in]);
|
||||||
dup2(stdout_pipe[stdout_fileno], stdout_fileno);
|
dup2(pipes[stdout_out], stdout_fileno);
|
||||||
|
|
||||||
|
if ( stdin_towrite )
|
||||||
|
{
|
||||||
|
close(pipes[stdin_out]);
|
||||||
|
dup2(pipes[stdin_in], stdin_fileno);
|
||||||
|
}
|
||||||
|
|
||||||
//execv("/usr/bin/uname",test);
|
//execv("/usr/bin/uname",test);
|
||||||
execl("/bin/sh", "sh", "-c", fname.c_str(), NULL);
|
execl("/bin/sh", "sh", "-c", fname.c_str(), NULL);
|
||||||
fprintf(stderr, "Exec failed :(......\n");
|
fprintf(stderr, "Exec failed :(......\n");
|
||||||
|
@ -87,12 +97,18 @@ bool Raw::Execute()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we are the parent
|
// we are the parent
|
||||||
close(stdout_pipe[stdout_fileno]);
|
close(pipes[stdout_out]);
|
||||||
|
|
||||||
if ( Info().mode == MODE_STREAM )
|
if ( Info().mode == MODE_STREAM )
|
||||||
fcntl(stdout_pipe[stdin_fileno], F_SETFL, O_NONBLOCK);
|
fcntl(pipes[stdout_in], F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
if ( stdin_towrite )
|
||||||
|
{
|
||||||
|
close(pipes[stdin_in]);
|
||||||
|
fcntl(pipes[stdin_out], F_SETFL, O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
file = fdopen(stdout_pipe[stdin_fileno], "r");
|
file = fdopen(pipes[stdout_in], "r");
|
||||||
if ( file == 0 )
|
if ( file == 0 )
|
||||||
{
|
{
|
||||||
Error("Could not convert fileno to file");
|
Error("Could not convert fileno to file");
|
||||||
|
@ -106,8 +122,7 @@ bool Raw::OpenInput()
|
||||||
{
|
{
|
||||||
if ( execute )
|
if ( execute )
|
||||||
{
|
{
|
||||||
if ( ! Execute() )
|
return Execute();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -120,10 +135,6 @@ bool Raw::OpenInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if ( execute && Info().mode == MODE_STREAM )
|
|
||||||
// fcntl(fileno(file), F_SETFL, O_NONBLOCK);
|
|
||||||
|
|
||||||
//fcntl(fileno(file), F_SETFD, FD_CLOEXEC);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +149,11 @@ bool Raw::CloseInput()
|
||||||
Debug(DBG_INPUT, "Raw reader starting close");
|
Debug(DBG_INPUT, "Raw reader starting close");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( execute )
|
if ( execute ) // we do not care if any of those fails. They should all be defined.
|
||||||
pclose(file);
|
{
|
||||||
|
for ( int i = 0; i < 6; i ++ )
|
||||||
|
close(pipes[i]);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
|
@ -166,6 +180,13 @@ bool Raw::DoInit(const ReaderInfo& info, int num_fields, const Field* const* fie
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map<const char*, const char*>::const_iterator it = info.config.find("stdin"); // data that is sent to the child process
|
||||||
|
if ( it != info.config.end() )
|
||||||
|
{
|
||||||
|
stdin_string = it->second;
|
||||||
|
stdin_towrite = stdin_string.length();
|
||||||
|
}
|
||||||
|
|
||||||
if ( num_fields != 1 )
|
if ( num_fields != 1 )
|
||||||
{
|
{
|
||||||
Error("Filter for raw reader contains more than one field. "
|
Error("Filter for raw reader contains more than one field. "
|
||||||
|
@ -214,9 +235,8 @@ bool Raw::DoInit(const ReaderInfo& info, int num_fields, const Field* const* fie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int64_t Raw::GetLine()
|
int64_t Raw::GetLine(FILE* arg_file)
|
||||||
{
|
{
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
uint64_t pos = 0;
|
uint64_t pos = 0;
|
||||||
|
|
||||||
|
@ -227,7 +247,7 @@ int64_t Raw::GetLine()
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
size_t readbytes = fread(buf+bufpos, 1, block_size-bufpos, file);
|
size_t readbytes = fread(buf+bufpos, 1, block_size-bufpos, arg_file);
|
||||||
pos += bufpos + readbytes;
|
pos += bufpos + readbytes;
|
||||||
bufpos = 0; // read full block size in next read...
|
bufpos = 0; // read full block size in next read...
|
||||||
|
|
||||||
|
@ -240,7 +260,7 @@ int64_t Raw::GetLine()
|
||||||
{
|
{
|
||||||
// we did not find it and have to search again in the next try. resize buffer....
|
// we did not find it and have to search again in the next try. resize buffer....
|
||||||
// but first check if we encountered the file end - because if we did this was it.
|
// but first check if we encountered the file end - because if we did this was it.
|
||||||
if ( feof(file) != 0 )
|
if ( feof(arg_file) != 0 )
|
||||||
{
|
{
|
||||||
outbuf = buf;
|
outbuf = buf;
|
||||||
buf = 0;
|
buf = 0;
|
||||||
|
@ -291,6 +311,28 @@ int64_t Raw::GetLine()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write to the stdin of the child process
|
||||||
|
void Raw::WriteToStdin()
|
||||||
|
{
|
||||||
|
assert(stdin_towrite <= stdin_string.length());
|
||||||
|
uint64_t pos = stdin_string.length() - stdin_towrite;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ssize_t written = write(pipes[stdin_out], stdin_string.c_str() + pos, stdin_towrite);
|
||||||
|
stdin_towrite -= written;
|
||||||
|
|
||||||
|
if ( errno != 0 && errno != EAGAIN && errno != EWOULDBLOCK )
|
||||||
|
{
|
||||||
|
Error(Fmt("Writing to child process stdin failed: %d. Stopping writing at position %d", errno, pos));
|
||||||
|
stdin_towrite = 0;
|
||||||
|
close(pipes[stdin_out]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( stdin_towrite == 0 ) // send EOF when we are done.
|
||||||
|
printf("Closing %d\n", pipes[stdin_out]);
|
||||||
|
close(pipes[stdin_out]);
|
||||||
|
}
|
||||||
|
|
||||||
// read the entire file and send appropriate thingies back to InputMgr
|
// read the entire file and send appropriate thingies back to InputMgr
|
||||||
bool Raw::DoUpdate()
|
bool Raw::DoUpdate()
|
||||||
{
|
{
|
||||||
|
@ -344,8 +386,11 @@ bool Raw::DoUpdate()
|
||||||
assert (NumFields() == 1);
|
assert (NumFields() == 1);
|
||||||
for ( ;; )
|
for ( ;; )
|
||||||
{
|
{
|
||||||
int64_t length = GetLine();
|
if ( stdin_towrite > 0 )
|
||||||
//printf("Read %lld bytes", length);
|
WriteToStdin();
|
||||||
|
|
||||||
|
int64_t length = GetLine(file);
|
||||||
|
//printf("Read %lld bytes\n", length);
|
||||||
|
|
||||||
if ( length == -3 )
|
if ( length == -3 )
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -29,7 +29,9 @@ protected:
|
||||||
private:
|
private:
|
||||||
bool OpenInput();
|
bool OpenInput();
|
||||||
bool CloseInput();
|
bool CloseInput();
|
||||||
int64_t GetLine();
|
int64_t GetLine(FILE* file);
|
||||||
|
bool Execute();
|
||||||
|
void WriteToStdin();
|
||||||
|
|
||||||
string fname; // Source with a potential "|" removed.
|
string fname; // Source with a potential "|" removed.
|
||||||
FILE* file;
|
FILE* file;
|
||||||
|
@ -40,10 +42,9 @@ private:
|
||||||
// options set from the script-level.
|
// options set from the script-level.
|
||||||
string separator;
|
string separator;
|
||||||
unsigned int sep_length; // length of the separator
|
unsigned int sep_length; // length of the separator
|
||||||
bool Execute();
|
|
||||||
|
|
||||||
static const int block_size;
|
static const int block_size;
|
||||||
uint32_t bufpos;
|
uint64_t bufpos;
|
||||||
char* buf;
|
char* buf;
|
||||||
char* outbuf;
|
char* outbuf;
|
||||||
|
|
||||||
|
@ -51,7 +52,21 @@ private:
|
||||||
int stdout_fileno;
|
int stdout_fileno;
|
||||||
int stderr_fileno;
|
int stderr_fileno;
|
||||||
|
|
||||||
|
string stdin_string;
|
||||||
|
uint64_t stdin_towrite;
|
||||||
|
|
||||||
|
int pipes[6];
|
||||||
pid_t childpid;
|
pid_t childpid;
|
||||||
|
|
||||||
|
enum IoChannels {
|
||||||
|
stdout_in = 0,
|
||||||
|
stdout_out = 1,
|
||||||
|
stdin_in = 2,
|
||||||
|
stdin_out = 3,
|
||||||
|
stderr_in = 4,
|
||||||
|
stderr_out = 5
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
[source=cat |, reader=Input::READER_RAW, mode=Input::STREAM, name=input2, fields=<no value description>, want_record=F, ev=line
|
||||||
|
{
|
||||||
|
print outfile, A::description;
|
||||||
|
print outfile, A::tpe;
|
||||||
|
print outfile, A::s;
|
||||||
|
try = try + 1;
|
||||||
|
if (2 == try)
|
||||||
|
{
|
||||||
|
Input::remove(input2);
|
||||||
|
close(outfile);
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, config={
|
||||||
|
[stdin] = hello^Jthere^A^B^C^D^E^A^B^Cyay
|
||||||
|
}]
|
||||||
|
Input::EVENT_NEW
|
||||||
|
hello
|
||||||
|
[source=cat |, reader=Input::READER_RAW, mode=Input::STREAM, name=input2, fields=<no value description>, want_record=F, ev=line
|
||||||
|
{
|
||||||
|
print outfile, A::description;
|
||||||
|
print outfile, A::tpe;
|
||||||
|
print outfile, A::s;
|
||||||
|
try = try + 1;
|
||||||
|
if (2 == try)
|
||||||
|
{
|
||||||
|
Input::remove(input2);
|
||||||
|
close(outfile);
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, config={
|
||||||
|
[stdin] = hello^Jthere^A^B^C^D^E^A^B^Cyay
|
||||||
|
}]
|
||||||
|
Input::EVENT_NEW
|
||||||
|
there^A^B^C^D^E^A^B^Cyay
|
|
@ -0,0 +1,2 @@
|
||||||
|
hello
|
||||||
|
thereyay
|
44
testing/btest/scripts/base/frameworks/input/execrawstdin.bro
Normal file
44
testing/btest/scripts/base/frameworks/input/execrawstdin.bro
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
|
||||||
|
# @TEST-EXEC: btest-bg-wait -k 5
|
||||||
|
# @TEST-EXEC: btest-diff test.txt
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
|
||||||
|
redef exit_only_after_terminate = T;
|
||||||
|
@load base/frameworks/communication # let network-time run. otherwise there are no heartbeats...
|
||||||
|
|
||||||
|
global outfile: file;
|
||||||
|
global try: count;
|
||||||
|
|
||||||
|
module A;
|
||||||
|
|
||||||
|
type Val: record {
|
||||||
|
s: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
event line(description: Input::EventDescription, tpe: Input::Event, s: string)
|
||||||
|
{
|
||||||
|
print outfile, description;
|
||||||
|
print outfile, tpe;
|
||||||
|
print outfile, s;
|
||||||
|
try = try + 1;
|
||||||
|
if ( try == 2 )
|
||||||
|
{
|
||||||
|
Input::remove("input2");
|
||||||
|
close(outfile);
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
local config_strings: table[string] of string = {
|
||||||
|
["stdin"] = "hello\nthere\1\2\3\4\5\1\2\3yay"
|
||||||
|
#["stdin"] = "yay"
|
||||||
|
};
|
||||||
|
|
||||||
|
try = 0;
|
||||||
|
outfile = open("../out");
|
||||||
|
Input::add_event([$source="cat > ../test.txt |", $reader=Input::READER_RAW, $mode=Input::STREAM, $name="input", $fields=Val, $ev=line, $want_record=F, $config=config_strings]);
|
||||||
|
Input::remove("input");
|
||||||
|
Input::add_event([$source="cat |", $reader=Input::READER_RAW, $mode=Input::STREAM, $name="input2", $fields=Val, $ev=line, $want_record=F, $config=config_strings]);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue