implement live parse+execution
This commit is contained in:
parent
800ee2b651
commit
e2e2300337
12 changed files with 445 additions and 105 deletions
|
|
@ -23,7 +23,7 @@ echo '#ifndef G_VERSION_H' > "$tmpfile"
|
||||||
echo '#define G_VERSION_H' >> "$tmpfile"
|
echo '#define G_VERSION_H' >> "$tmpfile"
|
||||||
for I in "$codedir"/*.sh
|
for I in "$codedir"/*.sh
|
||||||
do
|
do
|
||||||
printf '#define %s "%s"\n' "$(basename "$I" | tr [:lower:] [:upper:] | tr '.' '_')" "$(minimize "$I" | to_cstr)" >> "$tmpfile"
|
printf '#define %s "%s\\n"\n' "$(basename "$I" | tr [:lower:] [:upper:] | tr '.' '_')" "$(minimize "$I" | to_cstr)" >> "$tmpfile"
|
||||||
done
|
done
|
||||||
echo "#endif" >> "$tmpfile"
|
echo "#endif" >> "$tmpfile"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,25 @@
|
||||||
|
|
||||||
#include "struc.hpp"
|
#include "struc.hpp"
|
||||||
|
|
||||||
bool r_debashify(_obj* o);
|
#include <map>
|
||||||
|
|
||||||
|
typedef struct debashify_params {
|
||||||
|
bool need_random_string=false;
|
||||||
|
bool need_random_tmpfile=false;
|
||||||
|
bool need_array_create=false;
|
||||||
|
bool need_array_set=false;
|
||||||
|
bool need_array_get=false;
|
||||||
|
bool need_map_create=false;
|
||||||
|
bool need_map_set=false;
|
||||||
|
bool need_map_get=false;
|
||||||
|
// map of detected arrays
|
||||||
|
// bool value: is associative
|
||||||
|
std::map<std::string,bool> arrays;
|
||||||
|
} debashify_params;
|
||||||
|
|
||||||
|
bool r_debashify(_obj* o, debashify_params* params);
|
||||||
|
|
||||||
|
void debashify(_obj* o, debashify_params* params);
|
||||||
void debashify(shmain* sh);
|
void debashify(shmain* sh);
|
||||||
|
|
||||||
#endif //DEBASHIFY_HPP
|
#endif //DEBASHIFY_HPP
|
||||||
|
|
|
||||||
12
include/exec.hpp
Normal file
12
include/exec.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef EXEC_HPP
|
||||||
|
#define EXEC_HPP
|
||||||
|
|
||||||
|
#include "options.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
void parse_exec(FILE* fd, const char* in, uint32_t size, std::string const& filename="");
|
||||||
|
inline void parse_exec(FILE* fd, std::string const& in, std::string const& filename="") { parse_exec(fd, in.c_str(), in.size(), filename); }
|
||||||
|
|
||||||
|
int exec_process(std::string const& runtime, std::vector<std::string> const& args, std::string const& filecontents, std::string const& file);
|
||||||
|
|
||||||
|
#endif //EXEC_HPP
|
||||||
|
|
@ -26,6 +26,13 @@
|
||||||
// bash specific
|
// bash specific
|
||||||
#define ARRAY_ARG_END " \t\n;#()&|<>]"
|
#define ARRAY_ARG_END " \t\n;#()&|<>]"
|
||||||
|
|
||||||
|
// macros
|
||||||
|
#define PARSE_ERROR(str, i) ztd::format_error(str, "", in, i)
|
||||||
|
|
||||||
|
// globals
|
||||||
|
|
||||||
|
extern bool g_bash;
|
||||||
|
|
||||||
extern const std::vector<std::string> posix_cmdvar;
|
extern const std::vector<std::string> posix_cmdvar;
|
||||||
extern const std::vector<std::string> bash_cmdvar;
|
extern const std::vector<std::string> bash_cmdvar;
|
||||||
|
|
||||||
|
|
@ -38,6 +45,12 @@ inline shmain* parse(std::string const& file) { return parse_text(import_file(fi
|
||||||
// ** unit parsers ** //
|
// ** unit parsers ** //
|
||||||
|
|
||||||
/* util parsers */
|
/* util parsers */
|
||||||
|
bool word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set=NULL);
|
||||||
|
std::pair<std::string,uint32_t> get_word(const char* in, uint32_t size, uint32_t start, const char* end_set);
|
||||||
|
uint32_t skip_chars(const char* in, uint32_t size, uint32_t start, const char* set);
|
||||||
|
uint32_t skip_until(const char* in, uint32_t size, uint32_t start, const char* set);
|
||||||
|
uint32_t skip_unread(const char* in, uint32_t size, uint32_t start);
|
||||||
|
|
||||||
// list
|
// list
|
||||||
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, char end_c, const char* expecting=NULL);
|
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, char end_c, const char* expecting=NULL);
|
||||||
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word);
|
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word);
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,15 @@
|
||||||
|
|
||||||
extern std::vector<std::string> included;
|
extern std::vector<std::string> included;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, std::string const& filename, std::string* ex_dir=nullptr);
|
||||||
|
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string const& filename, std::string* ex_dir=nullptr);
|
||||||
|
|
||||||
bool add_include(std::string const& file);
|
bool add_include(std::string const& file);
|
||||||
|
|
||||||
void resolve(_obj* sh, shmain* parent);
|
void resolve(_obj* sh, std::string* filename);
|
||||||
void resolve(shmain* sh);
|
void resolve(shmain* sh);
|
||||||
|
|
||||||
|
std::string _pre_cd(std::string const& filename);
|
||||||
|
void _cd(std::string const& dir);
|
||||||
|
|
||||||
#endif //RESOLVE_HPP
|
#endif //RESOLVE_HPP
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,8 @@ public:
|
||||||
list(condlist* in) { type=_obj::_list; this->add(in); }
|
list(condlist* in) { type=_obj::_list; this->add(in); }
|
||||||
~list() { for(auto it: cls) delete it; }
|
~list() { for(auto it: cls) delete it; }
|
||||||
|
|
||||||
|
void clear() { for(auto it: cls) delete it; cls.resize(0); }
|
||||||
|
|
||||||
std::vector<condlist*> cls;
|
std::vector<condlist*> cls;
|
||||||
inline void add(condlist* in) { cls.push_back(in); }
|
inline void add(condlist* in) { cls.push_back(in); }
|
||||||
|
|
||||||
|
|
@ -340,8 +342,6 @@ public:
|
||||||
if(lst!=nullptr) delete lst;
|
if(lst!=nullptr) delete lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_dev_file() { return filename.substr(0,5) == "/dev/"; }
|
|
||||||
|
|
||||||
void concat(shmain* in);
|
void concat(shmain* in);
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ std::string cut_last(std::string const& in, char c);
|
||||||
std::string basename(std::string const& in);
|
std::string basename(std::string const& in);
|
||||||
std::string dirname(std::string const& in);
|
std::string dirname(std::string const& in);
|
||||||
|
|
||||||
|
inline bool is_dev_file(std::string const& filename) { return filename.substr(0,5) == "/dev/"; }
|
||||||
|
|
||||||
std::string indent(int n);
|
std::string indent(int n);
|
||||||
|
|
||||||
bool is_among(std::string const& in, std::vector<std::string> const& values);
|
bool is_among(std::string const& in, std::vector<std::string> const& values);
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,6 @@
|
||||||
#include "g_shellcode.h"
|
#include "g_shellcode.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct debashify_params {
|
|
||||||
bool need_random_string=false;
|
|
||||||
bool need_random_tmpfile=false;
|
|
||||||
bool need_array_create=false;
|
|
||||||
bool need_array_set=false;
|
|
||||||
bool need_array_get=false;
|
|
||||||
bool need_map_create=false;
|
|
||||||
bool need_map_set=false;
|
|
||||||
bool need_map_get=false;
|
|
||||||
// map of detected arrays
|
|
||||||
// bool value: is associative
|
|
||||||
std::map<std::string,bool> arrays;
|
|
||||||
} debashify_params;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
[[ ]] debashifying:
|
[[ ]] debashifying:
|
||||||
[[ EXPRESSION && EXPRESSION ]] separated into two parts
|
[[ EXPRESSION && EXPRESSION ]] separated into two parts
|
||||||
|
|
@ -841,6 +826,12 @@ bool r_debashify(_obj* o, debashify_params* params)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void debashify(_obj* o, debashify_params* params)
|
||||||
|
{
|
||||||
|
recurse(r_debashify, o, params);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
void debashify(shmain* sh)
|
void debashify(shmain* sh)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
289
src/exec.cpp
Normal file
289
src/exec.cpp
Normal file
|
|
@ -0,0 +1,289 @@
|
||||||
|
#include "exec.hpp"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "g_shellcode.h"
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
#include "parse.hpp"
|
||||||
|
#include "debashify.hpp"
|
||||||
|
#include "resolve.hpp"
|
||||||
|
#include "recursive.hpp"
|
||||||
|
|
||||||
|
#define PIPE_READ 0
|
||||||
|
#define PIPE_WRITE 1
|
||||||
|
|
||||||
|
std::vector<condlist*> do_include_exec(condlist* cmd, std::string const& filename, FILE* fd)
|
||||||
|
{
|
||||||
|
std::vector<condlist*> ret;
|
||||||
|
|
||||||
|
std::string dir;
|
||||||
|
auto incs=do_include_raw(cmd, filename, &dir);
|
||||||
|
|
||||||
|
for(auto it: incs)
|
||||||
|
{
|
||||||
|
parse_exec(fd, it.second, it.first);
|
||||||
|
}
|
||||||
|
// cd back
|
||||||
|
_cd(dir);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if first is nullptr: is a string
|
||||||
|
std::vector<condlist*> do_resolve_exec(condlist* cmd, std::string const& filename, FILE* fd)
|
||||||
|
{
|
||||||
|
std::vector<condlist*> ret;
|
||||||
|
|
||||||
|
std::pair<std::string,std::string> p;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// get
|
||||||
|
std::string dir;
|
||||||
|
p=do_resolve_raw(cmd, filename, &dir);
|
||||||
|
// do parse
|
||||||
|
parse_exec(fd, p.second, filename);
|
||||||
|
// cd back
|
||||||
|
_cd(dir);
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), '`'+p.first+'`', e.data(), e.where());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- OBJECT CALLS --
|
||||||
|
|
||||||
|
bool resolve_condlist_exec(condlist* in, std::string const& filename, FILE* fd)
|
||||||
|
{
|
||||||
|
cmd* tc = in->first_cmd();
|
||||||
|
if(tc == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string const& strcmd=tc->arg_string(0);
|
||||||
|
|
||||||
|
if(g_include && strcmd == "%include")
|
||||||
|
{
|
||||||
|
do_include_exec(in, filename, fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(g_resolve && strcmd == "%resolve")
|
||||||
|
{
|
||||||
|
do_resolve_exec(in, filename, fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool resolve_exec(condlist* in, std::string const& filename, FILE* fd)
|
||||||
|
{
|
||||||
|
if(!resolve_condlist_exec(in, filename, fd))
|
||||||
|
{
|
||||||
|
resolve(in, (std::string*) &filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char byte_to_char(uint8_t in)
|
||||||
|
{
|
||||||
|
uint8_t t = in&0b00111111; // equiv to %64
|
||||||
|
if(t < 26)
|
||||||
|
return t+'a';
|
||||||
|
if(t < 52)
|
||||||
|
return (t-26)+'A';
|
||||||
|
if(t < 62)
|
||||||
|
return (t-52)+'0';
|
||||||
|
if(t == 62)
|
||||||
|
return '-';
|
||||||
|
return '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gettmpdir()
|
||||||
|
{
|
||||||
|
std::string tmpdir;
|
||||||
|
char* tbuf = getenv("TMPDIR");
|
||||||
|
if(tbuf != NULL)
|
||||||
|
tmpdir = tbuf;
|
||||||
|
if(tmpdir == "")
|
||||||
|
tmpdir = "/tmp";
|
||||||
|
return tmpdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// random string of size 20
|
||||||
|
std::string random_string()
|
||||||
|
{
|
||||||
|
// get system random seed
|
||||||
|
FILE* f = fopen("/dev/urandom", "r");
|
||||||
|
if(!f)
|
||||||
|
throw std::runtime_error("Cannot open stream to /dev/urandom");
|
||||||
|
uint8_t buffer[20];
|
||||||
|
size_t r = fread(buffer, 20, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
if(r<=0)
|
||||||
|
throw std::runtime_error("Cannot read from /dev/urandom");
|
||||||
|
|
||||||
|
std::string ret;
|
||||||
|
for(uint8_t i=0; i<20; i++)
|
||||||
|
ret += byte_to_char(buffer[i]);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_exec(FILE* fd, const char* in, uint32_t size, std::string const& filename)
|
||||||
|
{
|
||||||
|
uint32_t i=skip_unread(in, size, 0);
|
||||||
|
#ifndef NO_PARSE_CATCH
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
debashify_params debash_params;
|
||||||
|
list* t_lst=new list;
|
||||||
|
if(t_lst == nullptr)
|
||||||
|
throw std::runtime_error("Alloc error");
|
||||||
|
while(i<size)
|
||||||
|
{
|
||||||
|
auto pp=parse_condlist(in, size, i);
|
||||||
|
i=pp.second;
|
||||||
|
t_lst->add(pp.first);
|
||||||
|
if(g_resolve || g_include)
|
||||||
|
{
|
||||||
|
if(resolve_exec(t_lst->cls[0], filename, fd))
|
||||||
|
{
|
||||||
|
t_lst->clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(options["debashify"])
|
||||||
|
debashify(t_lst, &debash_params);
|
||||||
|
|
||||||
|
|
||||||
|
std::string gen=t_lst->generate(0);
|
||||||
|
t_lst->clear();
|
||||||
|
|
||||||
|
fprintf(fd, "%s", gen.c_str());
|
||||||
|
|
||||||
|
if(i < size)
|
||||||
|
{
|
||||||
|
if(in[i] == '#')
|
||||||
|
; // skip here
|
||||||
|
else if(is_in(in[i], COMMAND_SEPARATOR))
|
||||||
|
i++; // skip on next char
|
||||||
|
else if(is_in(in[i], CONTROL_END))
|
||||||
|
throw PARSE_ERROR(strf("Unexpected token: '%c'", in[i]), i);
|
||||||
|
|
||||||
|
i = skip_unread(in, size, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete t_lst;
|
||||||
|
#ifndef NO_PARSE_CATCH
|
||||||
|
}
|
||||||
|
catch(ztd::format_error& e)
|
||||||
|
{
|
||||||
|
throw ztd::format_error(e.what(), e.where(), in, filename);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t forkexec(const char* bin, char *const args[])
|
||||||
|
{
|
||||||
|
pid_t child_pid;
|
||||||
|
// int tfd = dup(STDIN_FILENO);
|
||||||
|
// std::cout << tfd << std::endl;
|
||||||
|
if((child_pid = vfork()) == -1)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("fork() failed");
|
||||||
|
}
|
||||||
|
if (child_pid == 0) // child process
|
||||||
|
{
|
||||||
|
// char buf[1000] = {0};
|
||||||
|
// read(STDIN_FILENO, buf, 1000);
|
||||||
|
// std::cout << std::string(buf) << std::endl;
|
||||||
|
// std::cout << dup2(tfd, STDIN_FILENO) << std::endl;
|
||||||
|
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
|
||||||
|
execv(bin, args);
|
||||||
|
throw std::runtime_error("execv() failed");
|
||||||
|
}
|
||||||
|
else // main process
|
||||||
|
{
|
||||||
|
return child_pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int wait_pid(pid_t pid)
|
||||||
|
{
|
||||||
|
int stat;
|
||||||
|
while (waitpid(pid, &stat, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
stat = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WEXITSTATUS(stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec_process(std::string const& runtime, std::vector<std::string> const& args, std::string const& filecontents, std::string const& file)
|
||||||
|
{
|
||||||
|
std::vector<std::string> strargs = split(runtime, " \t");
|
||||||
|
std::vector<char*> runargs;
|
||||||
|
|
||||||
|
std::string fifopath=gettmpdir();
|
||||||
|
fifopath+="/lxshfiforun_";
|
||||||
|
fifopath+=random_string();
|
||||||
|
|
||||||
|
if(mkfifo(fifopath.c_str(), 0700)<0)
|
||||||
|
throw std::runtime_error("Cannot create fifo "+fifopath);
|
||||||
|
|
||||||
|
for(uint32_t i=0; i<strargs.size(); i++)
|
||||||
|
runargs.push_back((char*) strargs[i].c_str());
|
||||||
|
runargs.push_back((char*) fifopath.c_str());
|
||||||
|
for(uint32_t i=0; i<args.size(); i++)
|
||||||
|
runargs.push_back((char*) args[i].c_str());
|
||||||
|
runargs.push_back(NULL);
|
||||||
|
|
||||||
|
pid_t pid=0;
|
||||||
|
// std::string test="echo Hello world\nexit 10\n";
|
||||||
|
// fprintf(ffd, "%s\n",, test.c_str(), test.size());
|
||||||
|
FILE* ffd;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pid = forkexec(runargs[0], runargs.data());
|
||||||
|
ffd = fopen(fifopath.c_str(), "w");
|
||||||
|
if(options["debashify"])
|
||||||
|
{
|
||||||
|
fprintf(ffd, "%s\n", ARRAY_CREATE_SH);
|
||||||
|
fprintf(ffd, "%s\n", ARRAY_GET_SH);
|
||||||
|
fprintf(ffd, "%s\n", ARRAY_SET_SH);
|
||||||
|
fprintf(ffd, "%s\n", MAP_CREATE_SH);
|
||||||
|
fprintf(ffd, "%s\n", MAP_GET_SH);
|
||||||
|
fprintf(ffd, "%s\n", MAP_SET_SH);
|
||||||
|
fprintf(ffd, "%s\n", RANDOM_STRING_SH);
|
||||||
|
fprintf(ffd, "%s\n", RANDOM_TMPFILE_SH);
|
||||||
|
}
|
||||||
|
parse_exec(ffd, filecontents, file);
|
||||||
|
}
|
||||||
|
catch(std::runtime_error& e)
|
||||||
|
{
|
||||||
|
fclose(ffd);
|
||||||
|
unlink(fifopath.c_str());
|
||||||
|
if(pid != 0)
|
||||||
|
kill(pid, SIGINT);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(ffd);
|
||||||
|
unlink(fifopath.c_str());
|
||||||
|
|
||||||
|
return wait_pid(pid);
|
||||||
|
}
|
||||||
65
src/main.cpp
65
src/main.cpp
|
|
@ -16,6 +16,7 @@
|
||||||
#include "resolve.hpp"
|
#include "resolve.hpp"
|
||||||
#include "processing.hpp"
|
#include "processing.hpp"
|
||||||
#include "debashify.hpp"
|
#include "debashify.hpp"
|
||||||
|
#include "exec.hpp"
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "g_version.h"
|
#include "g_version.h"
|
||||||
|
|
@ -108,6 +109,8 @@ int main(int argc, char* argv[])
|
||||||
std::string file = args[i];
|
std::string file = args[i];
|
||||||
std::string filecontents=import_file(file);
|
std::string filecontents=import_file(file);
|
||||||
std::string shebang=filecontents.substr(0,filecontents.find('\n'));
|
std::string shebang=filecontents.substr(0,filecontents.find('\n'));
|
||||||
|
if(shebang.substr(0,2) != "#!")
|
||||||
|
shebang="#!/bin/sh";
|
||||||
// resolve shebang and parse leftover options
|
// resolve shebang and parse leftover options
|
||||||
if(first_run)
|
if(first_run)
|
||||||
{
|
{
|
||||||
|
|
@ -124,39 +127,52 @@ int main(int argc, char* argv[])
|
||||||
is_exec = shebang_is_bin;
|
is_exec = shebang_is_bin;
|
||||||
|
|
||||||
if(!is_exec && args.size() > 1) // not exec: parse options on args
|
if(!is_exec && args.size() > 1) // not exec: parse options on args
|
||||||
{
|
|
||||||
args=options.process(args);
|
args=options.process(args);
|
||||||
}
|
|
||||||
|
if(!is_exec && options['e'])
|
||||||
|
throw std::runtime_error("Option -e must be before file");
|
||||||
|
|
||||||
|
if(shebang_is_bin) // enable debashify option
|
||||||
|
options["debashify"].activated=true;
|
||||||
|
|
||||||
oneshot_opt_process(argv[0]);
|
oneshot_opt_process(argv[0]);
|
||||||
get_opts();
|
get_opts();
|
||||||
|
|
||||||
}
|
}
|
||||||
// parse
|
// parse
|
||||||
g_origin=file;
|
g_origin=file;
|
||||||
if(!add_include(file))
|
if(!add_include(file))
|
||||||
continue;
|
continue;
|
||||||
tsh = parse_text(filecontents, file);
|
|
||||||
if(shebang_is_bin) // resolve lxsh shebang to sh
|
|
||||||
{
|
|
||||||
options["debashify"].activated=true;
|
|
||||||
tsh->shebang="#!/bin/sh";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mid processing */
|
|
||||||
// resolve/include
|
|
||||||
if(g_include || g_resolve)
|
|
||||||
{
|
|
||||||
resolve(tsh);
|
|
||||||
}
|
|
||||||
|
|
||||||
// concatenate to main
|
|
||||||
sh->concat(tsh);
|
|
||||||
delete tsh;
|
|
||||||
tsh = nullptr;
|
|
||||||
|
|
||||||
// is exec: break and exec
|
|
||||||
if(is_exec)
|
if(is_exec)
|
||||||
break;
|
{
|
||||||
|
if(options["debashify"])
|
||||||
|
{
|
||||||
|
shebang = "#!/bin/sh";
|
||||||
|
}
|
||||||
|
if(options["debashify"] || basename(shebang) == "bash")
|
||||||
|
{
|
||||||
|
g_bash = true;
|
||||||
|
}
|
||||||
|
args.erase(args.begin());
|
||||||
|
return exec_process(shebang.substr(2), args, filecontents, file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tsh = parse_text(filecontents, file);
|
||||||
|
if(shebang_is_bin) // resolve lxsh shebang to sh
|
||||||
|
tsh->shebang="#!/bin/sh";
|
||||||
|
|
||||||
|
/* mid processing */
|
||||||
|
// resolve/include
|
||||||
|
if(g_include || g_resolve)
|
||||||
|
resolve(tsh);
|
||||||
|
|
||||||
|
// concatenate to main
|
||||||
|
sh->concat(tsh);
|
||||||
|
delete tsh;
|
||||||
|
tsh = nullptr;
|
||||||
|
}
|
||||||
} // end of argument parse
|
} // end of argument parse
|
||||||
|
|
||||||
if(options["debashify"])
|
if(options["debashify"])
|
||||||
|
|
@ -191,11 +207,6 @@ int main(int argc, char* argv[])
|
||||||
list_fcts(sh, re_fct_exclude);
|
list_fcts(sh, re_fct_exclude);
|
||||||
else if(options["list-cmd"])
|
else if(options["list-cmd"])
|
||||||
list_cmds(sh, regex_null);
|
list_cmds(sh, regex_null);
|
||||||
// execute
|
|
||||||
else if(is_exec)
|
|
||||||
{
|
|
||||||
ret = execute(sh, args);
|
|
||||||
}
|
|
||||||
// output
|
// output
|
||||||
else if(options['o']) // file output
|
else if(options['o']) // file output
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,6 @@ bool g_bash=false;
|
||||||
|
|
||||||
// macro
|
// macro
|
||||||
|
|
||||||
#define PARSE_ERROR(str, i) ztd::format_error(str, "", in, i)
|
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
const std::vector<std::string> posix_cmdvar = { "export", "unset", "local", "read", "getopts" };
|
const std::vector<std::string> posix_cmdvar = { "export", "unset", "local", "read", "getopts" };
|
||||||
const std::vector<std::string> bash_cmdvar = { "readonly", "declare", "typeset" };
|
const std::vector<std::string> bash_cmdvar = { "readonly", "declare", "typeset" };
|
||||||
|
|
@ -65,7 +63,7 @@ bool valid_name(std::string const& str)
|
||||||
|
|
||||||
// string utils
|
// string utils
|
||||||
|
|
||||||
bool word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set=NULL)
|
bool word_eq(const char* word, const char* in, uint32_t size, uint32_t start, const char* end_set)
|
||||||
{
|
{
|
||||||
uint32_t wordsize=strlen(word);
|
uint32_t wordsize=strlen(word);
|
||||||
if(wordsize > size-start)
|
if(wordsize > size-start)
|
||||||
|
|
|
||||||
111
src/resolve.cpp
111
src/resolve.cpp
|
|
@ -34,17 +34,18 @@ bool add_include(std::string const& file)
|
||||||
if(it == truepath)
|
if(it == truepath)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// std::cout << truepath << std::endl;
|
||||||
included.push_back(truepath);
|
included.push_back(truepath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns path to old dir
|
// returns path to old dir
|
||||||
std::string _pre_cd(shmain* parent)
|
std::string _pre_cd(std::string const& filename)
|
||||||
{
|
{
|
||||||
if(parent->is_dev_file() || parent->filename == "")
|
if(filename == "" || is_dev_file(filename))
|
||||||
return "";
|
return "";
|
||||||
std::string dir=pwd();
|
std::string dir=pwd();
|
||||||
std::string cddir=dirname(parent->filename);
|
std::string cddir=dirname(filename);
|
||||||
if(chdir(cddir.c_str()) != 0)
|
if(chdir(cddir.c_str()) != 0)
|
||||||
throw std::runtime_error("Cannot cd to '"+cddir+"'");
|
throw std::runtime_error("Cannot cd to '"+cddir+"'");
|
||||||
return dir;
|
return dir;
|
||||||
|
|
@ -59,7 +60,7 @@ void _cd(std::string const& dir)
|
||||||
// -- COMMANDS --
|
// -- COMMANDS --
|
||||||
|
|
||||||
// return <name, contents>[]
|
// return <name, contents>[]
|
||||||
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, shmain* parent, std::string* ex_dir=nullptr)
|
std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, std::string const& filename, std::string* ex_dir)
|
||||||
{
|
{
|
||||||
std::vector<std::pair<std::string, std::string>> ret;
|
std::vector<std::pair<std::string, std::string>> ret;
|
||||||
|
|
||||||
|
|
@ -77,7 +78,7 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
||||||
std::string dir;
|
std::string dir;
|
||||||
if(g_cd && !opts['C'])
|
if(g_cd && !opts['C'])
|
||||||
{
|
{
|
||||||
dir=_pre_cd(parent);
|
dir=_pre_cd(filename);
|
||||||
if(ex_dir!=nullptr)
|
if(ex_dir!=nullptr)
|
||||||
*ex_dir=dir;
|
*ex_dir=dir;
|
||||||
}
|
}
|
||||||
|
|
@ -104,31 +105,8 @@ std::vector<std::pair<std::string, std::string>> do_include_raw(condlist* cmd, s
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<condlist*> do_include_parse(condlist* cmd, shmain* parent)
|
|
||||||
{
|
|
||||||
std::vector<condlist*> ret;
|
|
||||||
|
|
||||||
std::string dir;
|
|
||||||
auto incs=do_include_raw(cmd, parent, &dir);
|
|
||||||
|
|
||||||
for(auto it: incs)
|
|
||||||
{
|
|
||||||
shmain* sh=parse_text(it.second, it.first);
|
|
||||||
resolve(sh);
|
|
||||||
// get the cls
|
|
||||||
ret.insert(ret.end(), sh->lst->cls.begin(), sh->lst->cls.end());
|
|
||||||
// safety and cleanup
|
|
||||||
sh->lst->cls.resize(0);
|
|
||||||
delete sh;
|
|
||||||
}
|
|
||||||
// cd back
|
|
||||||
_cd(dir);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, shmain* parent, std::string* ex_dir=nullptr)
|
std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, std::string const& filename, std::string* ex_dir)
|
||||||
{
|
{
|
||||||
std::pair<std::string, std::string> ret;
|
std::pair<std::string, std::string> ret;
|
||||||
|
|
||||||
|
|
@ -146,7 +124,7 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, shmain* parent
|
||||||
std::string dir;
|
std::string dir;
|
||||||
if(g_cd && !opts['C'])
|
if(g_cd && !opts['C'])
|
||||||
{
|
{
|
||||||
dir=_pre_cd(parent);
|
dir=_pre_cd(filename);
|
||||||
if(ex_dir!=nullptr)
|
if(ex_dir!=nullptr)
|
||||||
*ex_dir=dir;
|
*ex_dir=dir;
|
||||||
}
|
}
|
||||||
|
|
@ -175,8 +153,31 @@ std::pair<std::string, std::string> do_resolve_raw(condlist* cmd, shmain* parent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<condlist*> do_include_parse(condlist* cmd, std::string const& filename)
|
||||||
|
{
|
||||||
|
std::vector<condlist*> ret;
|
||||||
|
|
||||||
|
std::string dir;
|
||||||
|
auto incs=do_include_raw(cmd, filename, &dir);
|
||||||
|
|
||||||
|
for(auto it: incs)
|
||||||
|
{
|
||||||
|
shmain* sh=parse_text(it.second, it.first);
|
||||||
|
resolve(sh);
|
||||||
|
// get the cls
|
||||||
|
ret.insert(ret.end(), sh->lst->cls.begin(), sh->lst->cls.end());
|
||||||
|
// safety and cleanup
|
||||||
|
sh->lst->cls.resize(0);
|
||||||
|
delete sh;
|
||||||
|
}
|
||||||
|
// cd back
|
||||||
|
_cd(dir);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// if first is nullptr: is a string
|
// if first is nullptr: is a string
|
||||||
std::vector<condlist*> do_resolve_parse(condlist* cmd, shmain* parent)
|
std::vector<condlist*> do_resolve_parse(condlist* cmd, std::string const& filename)
|
||||||
{
|
{
|
||||||
std::vector<condlist*> ret;
|
std::vector<condlist*> ret;
|
||||||
|
|
||||||
|
|
@ -185,7 +186,7 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, shmain* parent)
|
||||||
{
|
{
|
||||||
// get
|
// get
|
||||||
std::string dir;
|
std::string dir;
|
||||||
p=do_resolve_raw(cmd, parent, &dir);
|
p=do_resolve_raw(cmd, filename, &dir);
|
||||||
// do parse
|
// do parse
|
||||||
shmain* sh = parse_text(p.second);
|
shmain* sh = parse_text(p.second);
|
||||||
resolve(sh);
|
resolve(sh);
|
||||||
|
|
@ -207,7 +208,7 @@ std::vector<condlist*> do_resolve_parse(condlist* cmd, shmain* parent)
|
||||||
|
|
||||||
// -- OBJECT CALLS --
|
// -- OBJECT CALLS --
|
||||||
|
|
||||||
std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, shmain* parent)
|
std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, std::string const& filename)
|
||||||
{
|
{
|
||||||
cmd* tc = in->first_cmd();
|
cmd* tc = in->first_cmd();
|
||||||
if(tc == nullptr)
|
if(tc == nullptr)
|
||||||
|
|
@ -216,14 +217,14 @@ std::pair< std::vector<condlist*> , bool > resolve_condlist(condlist* in, shmain
|
||||||
std::string const& strcmd=tc->arg_string(0);
|
std::string const& strcmd=tc->arg_string(0);
|
||||||
|
|
||||||
if(g_include && strcmd == "%include")
|
if(g_include && strcmd == "%include")
|
||||||
return std::make_pair(do_include_parse(in, parent), true);
|
return std::make_pair(do_include_parse(in, filename), true);
|
||||||
else if(g_resolve && strcmd == "%resolve")
|
else if(g_resolve && strcmd == "%resolve")
|
||||||
return std::make_pair(do_resolve_parse(in, parent), true);
|
return std::make_pair(do_resolve_parse(in, filename), true);
|
||||||
else
|
else
|
||||||
return std::make_pair(std::vector<condlist*>(), false);
|
return std::make_pair(std::vector<condlist*>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, shmain* parent, bool forcequote=false)
|
std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, std::string const& filename, bool forcequote=false)
|
||||||
{
|
{
|
||||||
std::vector<arg*> ret;
|
std::vector<arg*> ret;
|
||||||
if(in == nullptr)
|
if(in == nullptr)
|
||||||
|
|
@ -249,12 +250,12 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, shmain* parent, bool
|
||||||
std::string fulltext;
|
std::string fulltext;
|
||||||
if(g_include && strcmd == "%include")
|
if(g_include && strcmd == "%include")
|
||||||
{
|
{
|
||||||
for(auto it: do_include_raw(tc, parent) )
|
for(auto it: do_include_raw(tc, filename) )
|
||||||
fulltext += it.second;
|
fulltext += it.second;
|
||||||
}
|
}
|
||||||
else if(g_resolve && strcmd == "%resolve")
|
else if(g_resolve && strcmd == "%resolve")
|
||||||
{
|
{
|
||||||
fulltext = do_resolve_raw(tc, parent).second;
|
fulltext = do_resolve_raw(tc, filename).second;
|
||||||
}
|
}
|
||||||
else // skip
|
else // skip
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -323,7 +324,7 @@ std::pair< std::vector<arg*> , bool > resolve_arg(arg* in, shmain* parent, bool
|
||||||
|
|
||||||
// -- RECURSIVE CALL --
|
// -- RECURSIVE CALL --
|
||||||
|
|
||||||
bool r_resolve(_obj* o, shmain* parent)
|
bool r_resolve(_obj* o, std::string* filename)
|
||||||
{
|
{
|
||||||
switch(o->type)
|
switch(o->type)
|
||||||
{
|
{
|
||||||
|
|
@ -336,7 +337,7 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
auto t = dynamic_cast<list*>(o);
|
auto t = dynamic_cast<list*>(o);
|
||||||
for(uint32_t i=0 ; i<t->cls.size() ; i++)
|
for(uint32_t i=0 ; i<t->cls.size() ; i++)
|
||||||
{
|
{
|
||||||
auto r=resolve_condlist(t->cls[i], parent);
|
auto r=resolve_condlist(t->cls[i], *filename);
|
||||||
if(r.second)
|
if(r.second)
|
||||||
{
|
{
|
||||||
// add new cls after current
|
// add new cls after current
|
||||||
|
|
@ -349,7 +350,7 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolve(t->cls[i], parent);
|
resolve(t->cls[i], filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -359,7 +360,7 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
auto t = dynamic_cast<arglist*>(o);
|
auto t = dynamic_cast<arglist*>(o);
|
||||||
for(uint32_t i=0 ; i<t->size() ; i++)
|
for(uint32_t i=0 ; i<t->size() ; i++)
|
||||||
{
|
{
|
||||||
auto r=resolve_arg(t->args[i], parent);
|
auto r=resolve_arg(t->args[i], *filename);
|
||||||
if(r.first.size()>0)
|
if(r.first.size()>0)
|
||||||
{
|
{
|
||||||
// add new args
|
// add new args
|
||||||
|
|
@ -371,7 +372,7 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resolve(t->args[i], parent);
|
resolve(t->args[i], filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -381,12 +382,12 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
auto t = dynamic_cast<cmd*>(o);
|
auto t = dynamic_cast<cmd*>(o);
|
||||||
for(auto it: t->var_assigns) // var assigns
|
for(auto it: t->var_assigns) // var assigns
|
||||||
{
|
{
|
||||||
resolve_arg(it.second, parent, true); // force quoted
|
resolve_arg(it.second, *filename, true); // force quoted
|
||||||
resolve(it.second, parent);
|
resolve(it.second, filename);
|
||||||
}
|
}
|
||||||
for(auto it: t->redirs)
|
for(auto it: t->redirs)
|
||||||
resolve(it, parent);
|
resolve(it, filename);
|
||||||
resolve(t->args, parent);
|
resolve(t->args, filename);
|
||||||
return false;
|
return false;
|
||||||
}; break;
|
}; break;
|
||||||
case _obj::block_case :
|
case _obj::block_case :
|
||||||
|
|
@ -394,15 +395,15 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
auto t = dynamic_cast<case_block*>(o);
|
auto t = dynamic_cast<case_block*>(o);
|
||||||
for(auto sc: t->cases)
|
for(auto sc: t->cases)
|
||||||
{
|
{
|
||||||
resolve_arg(t->carg, parent, true); // force quoted
|
resolve_arg(t->carg, *filename, true); // force quoted
|
||||||
resolve(t->carg, parent);
|
resolve(t->carg, filename);
|
||||||
|
|
||||||
for(auto it: sc.first)
|
for(auto it: sc.first)
|
||||||
{
|
{
|
||||||
resolve_arg(it, parent, true); // force quoted
|
resolve_arg(it, *filename, true); // force quoted
|
||||||
resolve(it, parent);
|
resolve(it, filename);
|
||||||
}
|
}
|
||||||
resolve(sc.second, parent);
|
resolve(sc.second, filename);
|
||||||
}
|
}
|
||||||
}; break;
|
}; break;
|
||||||
default: break;
|
default: break;
|
||||||
|
|
@ -411,12 +412,12 @@ bool r_resolve(_obj* o, shmain* parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursive call of resolve
|
// recursive call of resolve
|
||||||
void resolve(_obj* in, shmain* parent)
|
void resolve(_obj* in, std::string* filename)
|
||||||
{
|
{
|
||||||
recurse(r_resolve, in, parent);
|
recurse(r_resolve, in, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolve(shmain* sh)
|
void resolve(shmain* sh)
|
||||||
{
|
{
|
||||||
recurse(r_resolve, sh, sh);
|
recurse(r_resolve, sh, &sh->filename);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue