Improve direct execution

+ Add -o option
+ Add shebang analysis
+ Implement missing cleanup
This commit is contained in:
Mateo Feron 2020-09-02 12:03:07 +02:00
parent 8777abda32
commit 72a77c7088
5 changed files with 114 additions and 28 deletions

View file

@ -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. <br>
> 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. <br>
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

View file

@ -34,7 +34,7 @@ std::string delete_brackets(std::string const& in);
std::string pwd();
void _exec(std::string const& bin, std::vector<std::string> const& args);
int _exec(std::string const& bin, std::vector<std::string> const& args);
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace);

View file

@ -12,6 +12,48 @@
#include "parse.hpp"
#include "options.hpp"
int execute(block& sh, std::vector<std::string>& 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)

View file

@ -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;
}

View file

@ -1,6 +1,10 @@
#include "util.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <ztd/shell.hpp>
@ -69,14 +73,40 @@ std::string pwd()
return std::string(buf);
}
void _exec(std::string const& bin, std::vector<std::string> const& args)
int _exec(std::string const& bin, std::vector<std::string> const& args)
{
std::vector<char*> 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
}
}
}