Extend runscript to allow file with content like: "/prog1 prm1; /prog2 prm2"
Tests are included. Signed-off-by: Justin Cinkelj <[email protected]> --- core/commands.cc | 39 ++++++++---- tests/tst-commands.cc | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 12 deletions(-) diff --git a/core/commands.cc b/core/commands.cc index ebcac89..90fd1f2 100644 --- a/core/commands.cc +++ b/core/commands.cc @@ -85,16 +85,23 @@ parse_command_line_min(const std::string line, bool &ok) /* If cmd starts with "runcript file", read content of file and -update cmd with the content. +return vector of all programs to be run. +File can contain multiple commands per line. ok flag is set to false on parse error, and left unchanged otherwise. + +If cmd doesn't start with runscript, then vector with size 0 is returned. */ -void runscript_expand(std::vector<std::string>& cmd, bool &ok) +std::vector<std::vector<std::string>> runscript_expand(const std::vector<std::string>& cmd, bool &ok) { + std::vector<std::vector<std::string> > result; if (cmd[0] == "runscript") { - if (cmd.size()<2) { - puts("Failed expanding runscript - filename missing."); + /* + The cmd vector ends with additional ";" or "\0" element. + */ + if (cmd.size() != 3 && cmd[2].c_str()[0] != 0x00) { + puts("Failed expanding runscript - filename missing or extra parameters present."); ok = false; - return; + return result; } auto fn = cmd[1]; @@ -102,24 +109,22 @@ void runscript_expand(std::vector<std::string>& cmd, bool &ok) std::string line; // only first line up to \n is used. getline(in, line); - std::vector<std::vector<std::string> > result; bool ok2; result = parse_command_line_min(line, ok2); debug("runscript expand fn='%s' line='%s'\n", fn.c_str(), line.c_str()); if (ok2 == false) { printf("Failed expanding runscript file='%s' line='%s'.\n", fn.c_str(), line.c_str()); + result.clear(); ok = false; } - else { - cmd = result[0]; - } } + return result; } std::vector<std::vector<std::string>> parse_command_line(const std::string line, bool &ok) { - std::vector<std::vector<std::string> > result; + std::vector<std::vector<std::string> > result, result2; result = parse_command_line_min(line, ok); /* @@ -127,8 +132,18 @@ parse_command_line(const std::string line, bool &ok) execute from the given file. */ std::vector<std::vector<std::string>>::iterator cmd_iter; - for (cmd_iter=result.begin(); ok && cmd_iter!=result.end(); cmd_iter++) { - runscript_expand(*cmd_iter, ok); + for (cmd_iter=result.begin(); ok && cmd_iter!=result.end(); ) { + result2 = runscript_expand(*cmd_iter, ok); + if (result2.size() > 0) { + cmd_iter = result.erase(cmd_iter); + int pos; + pos = cmd_iter - result.begin(); + result.insert(cmd_iter, result2.begin(), result2.end()); + cmd_iter = result.begin() + pos + result2.size(); + } + else { + cmd_iter++; + } } return result; diff --git a/tests/tst-commands.cc b/tests/tst-commands.cc index c6fb3a5..3b8c1c9 100644 --- a/tests/tst-commands.cc +++ b/tests/tst-commands.cc @@ -353,6 +353,168 @@ static bool test_runscript_multiple_with_args_quotes() return true; } +static bool test_runscript_multiple_commands_per_line() +{ + std::ofstream of1("/myscript", std::ios::out | std::ios::binary); + of1 << "/prog1; /prog2"; + of1.close(); + + std::vector<std::vector<std::string> > result; + std::vector<std::string> cmd = { "/prog1", "/prog2" }; + bool ok; + + result = osv::parse_command_line( + std::string("runscript \"/myscript\""), + ok); + + if (!ok) { + return false; + } + + if (result.size() != 2) { + return false; + } + + if (result[0].size() != 2) { + return false; + } + + if (result[1].size() != 2) { + return false; + } + + for (size_t i = 0; i < result.size(); i++) { + if (result[i][0] != cmd[i]) { + return false; + } + } + + return true; +} + +static bool test_runscript_multiple_commands_per_line_with_args() +{ + std::ofstream of1("/myscript", std::ios::out | std::ios::binary); + of1 << "/prog1 pp1a ; /prog2 pp2a pp2b"; + of1.close(); + + std::vector<std::vector<std::string> > result; + std::vector<std::string> cmd = { "/prog1", "/prog2" }; + bool ok; + + result = osv::parse_command_line( + std::string("runscript \"/myscript\""), + ok); + + if (!ok) { + return false; + } + + if (result.size() != 2) { + return false; + } + + if (result[0].size() != 3) { + return false; + } + + if (result[1].size() != 4) { + return false; + } + + for (size_t i = 0; i < result.size(); i++) { + if (result[i][0] != cmd[i]) { + return false; + } + } + + if (result[0][1] != std::string("pp1a")) { + return false; + } + + if (result[1][1] != std::string("pp2a")) { + return false; + } + if (result[1][2] != std::string("pp2b")) { + return false; + } + + return true; +} + +static bool test_runscript_multiple_commands_per_line_with_args_quotes() +{ + std::ofstream of1("/myscript", std::ios::out | std::ios::binary); + of1 << "/prog1 pp1a ; /prog2 pp2a pp2b; /prog3 pp3a \"pp3b1 pp3b2\" \"pp3c1;pp3c2\" \"pp3d\" \" ;; --onx -fon;x \\t\"; "; + of1.close(); + + std::vector<std::vector<std::string> > result; + std::vector<std::string> cmd = { "/prog1", "/prog2", "/prog3" }; + bool ok; + + result = osv::parse_command_line( + std::string("runscript \"/myscript\""), + ok); + + if (!ok) { + return false; + } + + if (result.size() != 3) { + return false; + } + + if (result[0].size() != 3) { + return false; + } + + if (result[1].size() != 4) { + return false; + } + + if (result[2].size() != 7) { + return false; + } + + for (size_t i = 0; i < result.size(); i++) { + if (result[i][0] != cmd[i]) { + return false; + } + } + + if (result[0][1] != std::string("pp1a")) { + return false; + } + + if (result[1][1] != std::string("pp2a")) { + return false; + } + if (result[1][2] != std::string("pp2b")) { + return false; + } + + if (result[2][1] != std::string("pp3a")) { + return false; + } + if (result[2][2] != std::string("pp3b1 pp3b2")) { + return false; + } + if (result[2][3] != std::string("pp3c1;pp3c2")) { + return false; + } + if (result[2][4] != std::string("pp3d")) { + return false; + } + if (result[2][5] != std::string(" ;; --onx -fon;x \t")) { + return false; + } + if (result[2][6] != std::string(";")) { + return false; + } + + return true; +} + int main(int argc, char *argv[]) { report(test_parse_simplest(), "simplest command line"); @@ -369,6 +531,12 @@ int main(int argc, char *argv[]) "cpiod upload and haproxy launch"); report(test_runscript_multiple_with_args_quotes(), "runscript multiple with args and quotes"); + report(test_runscript_multiple_commands_per_line(), + "runscript multiple commands per line"); + report(test_runscript_multiple_commands_per_line_with_args(), + "runscript multiple commands per line with args"); + report(test_runscript_multiple_commands_per_line_with_args_quotes(), + "runscript multiple commands per line with args and quotes"); printf("SUMMARY: %d tests, %d failures\n", tests, fails); return 0; } -- 2.5.5 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
