Improve direct execution
+ Add -o option + Add shebang analysis + Implement missing cleanup
This commit is contained in:
parent
8777abda32
commit
72a77c7088
5 changed files with 114 additions and 28 deletions
19
README.md
19
README.md
|
|
@ -16,9 +16,23 @@ These commands can be placed anywhere within the script like regular commands.
|
||||||
|
|
||||||
## Other features
|
## 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
|
### 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
|
### Minimize code
|
||||||
|
|
||||||
|
|
@ -30,5 +44,6 @@ lxsh should currently fully support POSIX syntax. <br>
|
||||||
A POSIX shell script should give a working output.
|
A POSIX shell script should give a working output.
|
||||||
|
|
||||||
Some specific features are missing:
|
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
|
- link commands placed on the same line as keywords `if`, `then`, `elif`, `else`, `for`, `while`, `do` or `done` are not resolved
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ std::string delete_brackets(std::string const& in);
|
||||||
|
|
||||||
std::string pwd();
|
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);
|
std::string stringReplace(std::string subject, const std::string& search, const std::string& replace);
|
||||||
|
|
||||||
|
|
|
||||||
81
src/main.cpp
81
src/main.cpp
|
|
@ -12,6 +12,48 @@
|
||||||
#include "parse.hpp"
|
#include "parse.hpp"
|
||||||
#include "options.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[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
auto args=options.process(argc, argv, false, true);
|
auto args=options.process(argc, argv, false, true);
|
||||||
|
|
@ -59,37 +101,36 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
g_origin=file;
|
g_origin=file;
|
||||||
add_include(file);
|
add_include(file);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
block sh(parse(import_file(file)));
|
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'])
|
if(options['e'])
|
||||||
{
|
{
|
||||||
std::string data=sh.generate();
|
return execute(sh, args);
|
||||||
// generate path
|
}
|
||||||
std::string tmpdir = (getenv("TMPDIR") != NULL) ? getenv("TMPDIR") : "/tmp" ;
|
else if(options['o'])
|
||||||
std::string filepath = tmpdir + "/lxsh_exec_" + ztd::sh("tr -dc '[:alnum:]' < /dev/urandom | head -c10");
|
{
|
||||||
// create stream
|
std::cout << sh.generate();
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << sh.generate();
|
if(binshebang == curbin)
|
||||||
|
{
|
||||||
|
return execute(sh, args);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << sh.generate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(ztd::format_error& e)
|
catch(ztd::format_error& e)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ ztd::option_set gen_options()
|
||||||
ztd::option_set ret;
|
ztd::option_set ret;
|
||||||
ret.add(ztd::option('h', "help", false, "Display this help message"));
|
ret.add(ztd::option('h', "help", false, "Display this help message"));
|
||||||
ret.add(ztd::option('m', "minimize", false, "Minimize code"));
|
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"));
|
ret.add(ztd::option("help-commands", false, "Print help for linker commands"));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
37
src/util.cpp
37
src/util.cpp
|
|
@ -1,6 +1,10 @@
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <ztd/shell.hpp>
|
#include <ztd/shell.hpp>
|
||||||
|
|
||||||
|
|
@ -69,14 +73,40 @@ std::string pwd()
|
||||||
return std::string(buf);
|
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;
|
std::vector<char*> rargs;
|
||||||
rargs.push_back((char*) bin.c_str());
|
|
||||||
for(auto it=args.begin(); it!=args.end(); it++)
|
for(auto it=args.begin(); it!=args.end(); it++)
|
||||||
rargs.push_back((char*) it->c_str());
|
rargs.push_back((char*) it->c_str());
|
||||||
rargs.push_back(NULL);
|
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)
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue