#include "debashify.hpp" #include "recursive.hpp" #include "util.hpp" #include "parse.hpp" #include "struc_helper.hpp" /* [[ ]] debashifying: [[ EXPRESSION && EXPRESSION ]] separated into two parts EXPRESSION : gen_bashtest_cmd && , || : debashify_bashtest */ // [[ $a = b ]] : quote vars // [[ a == b ]] : replace == with = // [[ a = b* ]] : case a in b*) true;; *) false;; esac // [[ a =~ b ]] : expr a : "b" >/dev/null block* gen_bashtest_cmd(std::vector args) { block* ret = nullptr; std::string arg1replace; if(args.size() == 3) { if(args[1]->string() == "==") arg1replace="="; else if(args[1]->string() == "<") arg1replace="-lt"; else if(args[1]->string() == "<=") arg1replace="-le"; else if(args[1]->string() == ">") arg1replace="-gt"; else if(args[1]->string() == ">=") arg1replace="-ge"; } if(arg1replace != "") { delete args[1]; args[1] = new arg(arg1replace); } if(args.size() == 3 && args[1]->string() == "=" && arg_has_char('*', args[2])) { delete args[1]; args[1]=nullptr; case_block* tc = new case_block(args[0]); tc->cases.push_back( std::make_pair(std::vector({args[2]}), make_list("true")) ); tc->cases.push_back( std::make_pair(std::vector({new arg("*")}), make_list("false")) ); ret = tc; } else if(args.size() == 3 && args[1]->string() == "=~") { delete args[1]; args[1]=nullptr; add_quotes(args[2]); ret = make_cmd( std::vector({ new arg("expr"), args[0], new arg(":"), args[2] }) ); ret->redirs.push_back(new redirect(">", new arg("/dev/null") )); } else // regular [ ] { cmd* t = make_cmd(args); t->args->insert(0, new arg("[")); t->add(new arg("]")); ret = t; } // arg oblivious replacements: // quote variables for(auto it: args) { if(it!=nullptr) force_quotes(it); } return ret; } // [[ a && b ]] : [ a ] && [ b ] bool debashify_bashtest(pipeline* pl) { if(pl->cmds.size()<=0) return false; if(pl->cmds[0]->type != _obj::block_cmd) return false; cmd* in = dynamic_cast(pl->cmds[0]); if(in->firstarg_string() == "[[") { brace* br = new brace(new list); condlist* cl = new condlist; br->lst->add(cl); arg *a=nullptr; uint32_t j=1; bool or_op=false; for(uint32_t i=1 ; iargs->size() ; i++) { a = in->args->args[i]; if(i >= in->args->size()-1 || a->string() == "&&" || a->string() == "||") { block* tbl = gen_bashtest_cmd(std::vector(in->args->args.begin()+j, in->args->args.begin()+i)); cl->add(new pipeline(tbl), or_op); or_op = a->string() == "||"; j=i+1; } } delete in->args->args[0]; delete in->args->args[in->args->args.size()-1]; in->args->args.resize(0); delete in; pl->cmds[0] = br; return true; } return false; } bool debashify_declare(cmd* in) { if(in->firstarg_string() == "declare") throw std::runtime_error("Cannot debashify 'declare'"); return false; } bool debashify_array_def(cmd* in) { for(auto it: in->var_assigns) { if(it.second->size()>0 && it.second->sa[0]->type == _obj::subarg_string && it.second->sa[0]->generate(0) == "(") throw std::runtime_error("Cannot debashify 'VAR=()' arrays"); } return false; } bool debashify_array_call(variable* in) { if(in->index != nullptr) throw std::runtime_error("Cannot debashify 'VAR[I]' arrays"); return false; } bool debashify_herestring(pipeline* pl) { if(pl->cmds.size()>0) { block* c=pl->cmds[0]; for(uint32_t i=0; iredirs.size() ; i++) { if(c->redirs[i]->op == "<<<") { force_quotes(c->redirs[i]->target); cmd* printcmd = make_cmd("printf '%s\\n'"); printcmd->add(c->redirs[i]->target); pl->cmds.insert(pl->cmds.begin(), printcmd); // cleanup c->redirs[i]->target=nullptr; delete c->redirs[i]; c->redirs.erase(pl->cmds[1]->redirs.begin()+i); return true; } } } return false; } // replace &>, &>> and >&: // add 2>&1 as redirect bool debashify_combined_redirects(block* in) { bool has_replaced=false; for(uint32_t i=0; iredirs.size() ; i++) { if(in->redirs[i]->op == "&>" || in->redirs[i]->op == "&>>" || in->redirs[i]->op == ">&") { // resolve new operator std::string newop = ">"; if( in->redirs[i]->op == "&>>" ) newop = ">>"; // create new redir with target redirect* newredir = new redirect(newop, in->redirs[i]->target); in->redirs[i]->target=nullptr; // replace old redir delete in->redirs[i]; in->redirs[i] = newredir; // insert merge redir i++; in->redirs.insert(in->redirs.begin()+i, new redirect("2>&1")); has_replaced=true; } } return has_replaced; } // replace <() and >() /* REPLACE TO: fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10) mkfifo "$fifoN" ( {PSUB;} [>|<] "$fifoN" ; rm "$fifoN") & CMD "$fifoN" */ bool debashify_procsub(list* lst) { bool has_replaced=false; for(uint32_t li=0; licls.size(); li++) { std::vector> affected_args; // iterate all applicable args of the cl for(auto plit: lst->cls[li]->pls) { for(auto cmit: plit->cmds) { if(cmit->type == _obj::block_cmd) { cmd* t = dynamic_cast(cmit); if(t->args != nullptr) { for(auto ait: t->args->args) { if(ait->size() == 1 && ait->sa[0]->type == _obj::subarg_procsub) { procsub_subarg* st = dynamic_cast(ait->sa[0]); affected_args.push_back( std::make_pair(ait, st->is_output) ); } } } } } } // perform the replace if(affected_args.size()>0) { has_replaced=true; list* lst_insert = new list; std::string mkfifocmd="mkfifo"; for(uint32_t i=0; iadd( make_condlist( strf("__lxshfifo%u=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10)", i) ) ); mkfifocmd += strf(" \"$__lxshfifo%u\"", i); } // mkfifo "$fifoN" lst_insert->add( make_condlist(mkfifocmd) ); for(uint32_t i=0; i "$fifoN" ; rm "$fifoN") & subshell* psub = new subshell(new list); procsub_subarg* st = dynamic_cast(affected_args[i].first->sa[0]); // {PSUB;} brace* cbr = new brace(st->sbsh->lst); // deindex list st->sbsh->lst=nullptr; // {PSUB;} > "$__lxshfifoN" cbr->redirs.push_back( new redirect( affected_args[i].second ? "<" : ">", make_arg(strf("\"$__lxshfifo%u\"", i)) ) ); // ( {PSUB;} > "$__lxshfifoN" ) psub->lst->add( new condlist(cbr) ); // ( {PSUB;} > "$__lxshfifoN" ; rm "$__lxshfifoN" ) psub->lst->add( make_condlist(strf("rm \"$__lxshfifo%u\"", i)) ); // ( {PSUB;} > "$__lxshfifoN" ; rm "$__lxshfifoN" ) & condlist* pscl = new condlist(psub); pscl->parallel=true; lst_insert->add( pscl ); // replace the arg delete affected_args[i].first->sa[0]; affected_args[i].first->sa[0] = new string_subarg("\""); affected_args[i].first->add( new variable_subarg( new variable(strf("__lxshfifo%u", i)) ) ); affected_args[i].first->add( new string_subarg("\"") ); } lst->insert(li, *lst_insert ); li+= lst_insert->size(); //cleanup lst_insert->cls.resize(0); delete lst_insert; } } return has_replaced; } function* create_random_func() { std::string code="{ tr -cd '[:alnum:]' name="__lxsh_random"; return fct; } bool r_debashify(_obj* o, bool* need_random_func) { switch(o->type) { case _obj::_variable: { variable* t = dynamic_cast(o); debashify_array_call(t); } break; case _obj::_list: { list* t = dynamic_cast(o); if(debashify_procsub(t)) *need_random_func = true; } break; case _obj::_pipeline: { pipeline* t = dynamic_cast(o); debashify_herestring(t); debashify_bashtest(t); } break; case _obj::block_cmd: { cmd* t = dynamic_cast(o); debashify_combined_redirects(t); debashify_declare(t); debashify_array_def(t); } break; case _obj::block_subshell: { subshell* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_brace: { brace* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_main: { shmain* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_function: { function* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_case: { case_block* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_if: { if_block* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_while: { while_block* t = dynamic_cast(o); debashify_combined_redirects(t); } break; case _obj::block_for: { for_block* t = dynamic_cast(o); debashify_combined_redirects(t); } break; default: break; } return true; } void debashify(shmain* sh) { bool need_random_func=false; sh->shebang = "#!/bin/sh"; recurse(r_debashify, sh, &need_random_func); if(need_random_func) sh->lst->insert(0, new condlist(create_random_func())); }