From 72a77c7088f1ad830999a9b8861c91951677b43f Mon Sep 17 00:00:00 2001 From: Mateo Feron Date: Wed, 2 Sep 2020 12:03:07 +0200 Subject: [PATCH] Improve direct execution + Add -o option + Add shebang analysis + Implement missing cleanup --- README.md | 19 ++++++++++-- include/util.hpp | 2 +- src/main.cpp | 81 ++++++++++++++++++++++++++++++++++++------------ src/options.cpp | 3 +- src/util.cpp | 37 +++++++++++++++++++--- 5 files changed, 114 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index b66cb82..ee499c2 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,23 @@ These commands can be placed anywhere within the script like regular commands. ## Other features +### Output generated code + +Output the generated shell code to stdout with either: +- `-o` option +- shebang other than lxsh + +> Redirect stdout to a file to create a script file.
+> The resulting script is not dependent on lxsh + ### Live execution -Execute an extended shell script directly with the `-e` option. +Directly execute an extended shell script with either +- `-e` option +- shebang is lxsh + +> Direct execution introduces direct dependency on lxsh and overhead, +> therefore it should be avoided outside of development use ### Minimize code @@ -30,5 +44,6 @@ lxsh should currently fully support POSIX syntax.
A POSIX shell script should give a working output. Some specific features are missing: -- link commands inside arithmetics (`$(())`) are not resolved +- link commands in subshells inside arithmetics are not resolved +- arithmetics cannot be minimized - link commands placed on the same line as keywords `if`, `then`, `elif`, `else`, `for`, `while`, `do` or `done` are not resolved diff --git a/include/util.hpp b/include/util.hpp index f4f6362..8f7dd27 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -34,7 +34,7 @@ std::string delete_brackets(std::string const& in); std::string pwd(); -void _exec(std::string const& bin, std::vector const& args); +int _exec(std::string const& bin, std::vector const& args); std::string stringReplace(std::string subject, const std::string& search, const std::string& replace); diff --git a/src/main.cpp b/src/main.cpp index cb43f9b..cb83856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,48 @@ #include "parse.hpp" #include "options.hpp" +int execute(block& sh, std::vector& args) +{ + std::string data=sh.generate(); + + std::string filename=ztd::exec("basename", args[0]).first; + filename.pop_back(); + + // generate path + std::string tmpdir = (getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp" ; + std::string dirpath = tmpdir + "/lxsh_" + ztd::sh("tr -dc '[:alnum:]' < /dev/urandom | head -c10"); + std::string filepath = dirpath+'/'+filename; + + // create dir + if(ztd::exec("mkdir", "-p", dirpath).second) + { + throw std::runtime_error("Failed to create directory '"+dirpath+'\''); + } + + // create stream + std::ofstream stream(filepath); + if(!stream) + { + ztd::exec("rm", "-rf", dirpath); + throw std::runtime_error("Failed to write to '"+filepath+'\''); + } + + // output + stream << data; + stream.close(); + if(ztd::exec("chmod", "+x", filepath).second != 0) + { + ztd::exec("rm", "-rf", dirpath); + throw std::runtime_error("Failed to make '"+filepath+"' executable"); + } + + // exec + int retval=_exec(filepath, args); + ztd::exec("rm", "-rf", dirpath); + + return retval; +} + int main(int argc, char* argv[]) { auto args=options.process(argc, argv, false, true); @@ -59,37 +101,36 @@ int main(int argc, char* argv[]) } } + g_origin=file; add_include(file); try { block sh(parse(import_file(file))); + std::string curbin, binshebang; + curbin=ztd::exec("basename", argv[0]).first; + binshebang=ztd::exec("basename", sh.shebang).first; + if(binshebang==curbin) + sh.shebang="#!/bin/sh"; if(options['e']) { - std::string data=sh.generate(); - // generate path - std::string tmpdir = (getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp" ; - std::string filepath = tmpdir + "/lxsh_exec_" + ztd::sh("tr -dc '[:alnum:]' < /dev/urandom | head -c10"); - // create stream - std::ofstream stream(filepath); - if(!stream) - throw std::runtime_error("Failed to write to file '"+filepath+'\''); - - // output - stream << data; - stream.close(); - auto p = ztd::exec("chmod", "+x", filepath); - if(p.second != 0) - return p.second; - - args.erase(args.begin()); - _exec(filepath, args); - + return execute(sh, args); + } + else if(options['o']) + { + std::cout << sh.generate(); } else { - std::cout << sh.generate(); + if(binshebang == curbin) + { + return execute(sh, args); + } + else + { + std::cout << sh.generate(); + } } } catch(ztd::format_error& e) diff --git a/src/options.cpp b/src/options.cpp index 33b09d9..a48e218 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -9,7 +9,8 @@ ztd::option_set gen_options() ztd::option_set ret; ret.add(ztd::option('h', "help", false, "Display this help message")); ret.add(ztd::option('m', "minimize", false, "Minimize code")); - ret.add(ztd::option('e', "exec", false, "Directly exec instead of outputting")); + ret.add(ztd::option('e', "exec", false, "Directly execute script")); + ret.add(ztd::option('o', "output", false, "Output result script to stdout")); ret.add(ztd::option("help-commands", false, "Print help for linker commands")); return ret; } diff --git a/src/util.cpp b/src/util.cpp index 76197a7..88d9a48 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,6 +1,10 @@ #include "util.hpp" #include +#include +#include + +#include #include @@ -69,14 +73,40 @@ std::string pwd() return std::string(buf); } -void _exec(std::string const& bin, std::vector const& args) +int _exec(std::string const& bin, std::vector const& args) { std::vector rargs; - rargs.push_back((char*) bin.c_str()); for(auto it=args.begin(); it!=args.end(); it++) rargs.push_back((char*) it->c_str()); rargs.push_back(NULL); - execvp(bin.c_str(), rargs.data()); + + pid_t pid; + + // forking + if((pid = fork()) == -1) + { + perror("fork"); + exit(1); + } + // child process + if(pid == 0) + { + setpgid(pid, pid); //Needed so negative PIDs can kill children of /bin/sh + execvp(bin.c_str(), rargs.data()); + exit(1); // exec didn't work + } + + int stat; + // wait for end and get return value + while (waitpid(pid, &stat, 0) == -1) + { + if (errno != EINTR) + { + stat = -1; + break; + } + } + return stat; } std::string stringReplace(std::string subject, const std::string& search, const std::string& replace) @@ -134,4 +164,3 @@ void printErrorIndex(const char* in, const int index, const std::string& message } } } -