/* -------------------------------------------------------------------------- * Copyright 2003-2011 (inclusive) Nathan Angelacos * (nangel@users.sourceforge.net) * * This file is part of haserl. * * Haserl is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation. * * Haserl is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with haserl. If not, see . * * ------------------------------------------------------------------------ */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SIGNAL_H #include #endif #include "common.h" #include "h_error.h" #include "h_bash.h" #include "h_script.h" #include "haserl.h" /* Local subshell variables */ static int subshell_pipe[2]; static int subshell_pid; void bash_setup (char *shell, list_t * env) { int retcode = 0; int count; argv_t *argv; char *av[20]; list_t *next; if (shell == NULL) return; retcode = pipe (&subshell_pipe[PARENT_IN]); if (retcode == 0) { subshell_pid = fork (); if (subshell_pid == -1) { die_with_message (NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } if (subshell_pid == 0) { /* I'm the child, connect stdin to the parent */ dup2 (subshell_pipe[PARENT_IN], STDIN_FILENO); close (subshell_pipe[PARENT_IN]); close (subshell_pipe[PARENT_OUT]); count = argc_argv (shell, &argv, ""); if (count > 19) { /* over 20 command line args, silently truncate */ av[19] = "\0"; count = 18; } while (count >= 0) { av[count] = argv[count].string; count--; } /* populate the environment */ while (env) { next = env->next; putenv (env->buf); env = next; } execv (argv[0].string, av); free (argv); /* if we get here, we had a failure */ die_with_message (NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } else { /* I'm parent, move along please */ close (subshell_pipe[PARENT_IN]); } } /* control should get to this point only in the parent. */ } void bash_destroy (void) { int status; waitpid (subshell_pid, &status, 0); } void bash_exec (buffer_t * buf, char *str) { buffer_add (buf, str, strlen (str)); return; } /* Run the echo command in a subshell */ void bash_echo (buffer_t * buf, char *str, size_t len) { /* limits.h would tell us the ARG_MAX characters we COULD send to the echo command, but * we will take the (ancient) POSIX1 standard of 4K, subtract 1K from it and use that * as the maxmimum. The Linux limit appears to be 128K, so 3K will fit. */ static char echo_start[] = "printf '%s' '"; static char echo_quote[] = "'\\''"; static char echo_end[] = "'\n"; const size_t maxlen = 3096; size_t pos; if (len == 0) return; pos = 0; buffer_add (buf, echo_start, strlen (echo_start)); while (pos < len) { if (str[pos] == '\'') buffer_add (buf, echo_quote, strlen (echo_quote)); else buffer_add (buf, str + pos, 1); pos++; if ((pos % maxlen) == 0) { buffer_add (buf, echo_end, strlen (echo_end)); buffer_add (buf, echo_start, strlen (echo_start)); } } buffer_add (buf, echo_end, strlen (echo_end)); } /* do an evaluation in a subshell */ void bash_eval (buffer_t * buf, char *str, size_t len) { static char echo_start[] = "echo -n "; static char echo_end[] = "\n"; if (len == 0) return; buffer_add (buf, echo_start, strlen (echo_start)); buffer_add (buf, str, len); buffer_add (buf, echo_end, strlen (echo_end)); } #ifdef BASHEXTENSIONS /* generate an IF statment */ void bash_if (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for if'\nexit 99\n"; static char if_start[] = "if [[ "; static char if_end[] = " ]]\nthen\n"; static char ex_start[] = "if "; static char ex_end[] = "\nthen\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else if (str[0] == '|') { str[0] = ' '; buffer_add (buf, ex_start, strlen (ex_start)); buffer_add (buf, str, len); buffer_add (buf, ex_end, strlen (ex_end)); } else { buffer_add (buf, if_start, strlen (if_start)); buffer_add (buf, str, len); buffer_add (buf, if_end, strlen (if_end)); } } /* generate an ELIF statment */ void bash_elif (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for elif'\nexit 99\n"; static char elif_start[] = "elif [[ "; static char elif_end[] = " ]]\nthen\n"; static char ex_start[] = "elif "; static char ex_end[] = "\nthen\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else if (str[0] == '|') { str[0] = ' '; buffer_add (buf, ex_start, strlen (ex_start)); buffer_add (buf, str, len); buffer_add (buf, ex_end, strlen (ex_end)); } else { buffer_add (buf, elif_start, strlen (elif_start)); buffer_add (buf, str, len); buffer_add (buf, elif_end, strlen (elif_end)); } } /* generate an ELSE statment */ void bash_else (buffer_t * buf, char *str, size_t len) { static char else_start[] = "else"; static char else_start2[] = "else #"; static char else_end[] = "\n"; if (len == 0) { buffer_add (buf, else_start, strlen (else_start)); } else { buffer_add (buf, else_start2, strlen (else_start2)); buffer_add (buf, str, len); } buffer_add (buf, else_end, strlen (else_end)); } /* generate a FI statment */ void bash_endif (buffer_t * buf, char *str, size_t len) { static char fi_start[] = "fi"; static char fi_start2[] = "fi #"; static char fi_end[] = "\n"; if (len == 0) { buffer_add (buf, fi_start, strlen (fi_start)); } else { buffer_add (buf, fi_start2, strlen (fi_start2)); buffer_add (buf, str, len); } buffer_add (buf, fi_end, strlen (fi_end)); } /* generate a CASE statment */ void bash_case (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for case'\nexit 99\n"; static char case_start[] = "case "; static char case_end[] = " in\n"; /* create a bogus case condition, nul+esc+eof, so nl+;;+nl can be prepended to each when/otherwise/endcase, which eliminates the need for ;; or <% ;; %> in the page source */ static char case_bogus[] = "\"\\000\\040\\004\") :\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else { buffer_add (buf, case_start, strlen (case_start)); buffer_add (buf, str, len); buffer_add (buf, case_end, strlen (case_end)); buffer_add (buf, case_bogus, strlen (case_bogus)); } } /* generate a WHEN statment */ void bash_when (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for when'\nexit 99\n"; static char when_start[] = "\n;;\n"; static char when_end[] = ")\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else { buffer_add (buf, when_start, strlen (when_start)); buffer_add (buf, str, len - 1); buffer_add (buf, when_end, strlen (when_end)); } } /* generate an OTHERWISE statment */ void bash_otherwise (buffer_t * buf, char *str, size_t len) { static char otherwise_start[] = "\n;;\n"; static char otherwise_start1[] = "*)"; static char otherwise_start2[] = "*) #"; static char otherwise_end[] = "\n"; buffer_add (buf, otherwise_start, strlen (otherwise_start)); if (len == 0) { buffer_add (buf, otherwise_start1, strlen (otherwise_start1)); } else { buffer_add (buf, otherwise_start2, strlen (otherwise_start2)); buffer_add (buf, str, len); } buffer_add (buf, otherwise_end, strlen (otherwise_end)); } /* generate a ENDCASE statment */ void bash_endcase (buffer_t * buf, char *str, size_t len) { static char endcase_start[] = "\n;;\n"; static char endcase_start1[] = "esac"; static char endcase_start2[] = "esac #"; static char endcase_end[] = "\n"; buffer_add (buf, endcase_start, strlen (endcase_start)); if (len == 0) { buffer_add (buf, endcase_start1, strlen (endcase_start1)); } else { buffer_add (buf, endcase_start2, strlen (endcase_start2)); buffer_add (buf, str, len); } buffer_add (buf, endcase_end, strlen (endcase_end)); } /* generate a WHILE statment */ void bash_while (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for while'\nexit 99\n"; static char while_start[] = "while [[ "; static char while_end[] = " ]]\ndo\n"; static char ex_start[] = "while "; static char ex_end[] = "\ndo\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else if (str[0] == '|') { str[0] = ' '; buffer_add (buf, ex_start, strlen (ex_start)); buffer_add (buf, str, len); buffer_add (buf, ex_end, strlen (ex_end)); } else { buffer_add (buf, while_start, strlen (while_start)); buffer_add (buf, str, len); buffer_add (buf, while_end, strlen (while_end)); } } /* generate an ENDWHILE statment */ void bash_endwhile (buffer_t * buf, char *str, size_t len) { static char endwhile_start[] = "done"; static char endwhile_start2[] = "done #"; static char endwhile_end[] = "\n"; if (len == 0) { buffer_add (buf, endwhile_start, strlen (endwhile_start)); } else { buffer_add (buf, endwhile_start2, strlen (endwhile_start2)); buffer_add (buf, str, len); } buffer_add (buf, endwhile_end, strlen (endwhile_end)); } /* generate an UNTIL statment */ void bash_until (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for until'\nexit 99\n"; static char until_start[] = "until [[ "; static char until_end[] = " ]]\ndo\n"; static char ex_start[] = "until "; static char ex_end[] = "\ndo\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else if (str[0] == '|') { str[0] = ' '; buffer_add (buf, ex_start, strlen (ex_start)); buffer_add (buf, str, len); buffer_add (buf, ex_end, strlen (ex_end)); } else { buffer_add (buf, until_start, strlen (until_start)); buffer_add (buf, str, len); buffer_add (buf, until_end, strlen (until_end)); } } /* generate an ENDUNTIL statment */ void bash_enduntil (buffer_t * buf, char *str, size_t len) { static char enduntil_start[] = "done"; static char enduntil_start2[] = "done #"; static char enduntil_end[] = "\n"; if (len == 0) { buffer_add (buf, enduntil_start, strlen (enduntil_start)); } else { buffer_add (buf, enduntil_start2, strlen (enduntil_start2)); buffer_add (buf, str, len); } buffer_add (buf, enduntil_end, strlen (enduntil_end)); } /* generate a FOR statment */ void bash_for (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for for'\nexit 99\n"; static char for_start[] = "for "; static char for_end[] = "\ndo\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else { buffer_add (buf, for_start, strlen (for_start)); buffer_add (buf, str, len); buffer_add (buf, for_end, strlen (for_end)); } } /* generate an ENDFOR statment */ void bash_endfor (buffer_t * buf, char *str, size_t len) { static char endfor_start[] = "done"; static char endfor_start2[] = "done #"; static char endfor_end[] = "\n"; if (len == 0) { buffer_add (buf, endfor_start, strlen (endfor_start)); } else { buffer_add (buf, endfor_start2, strlen (endfor_start2)); buffer_add (buf, str, len); } buffer_add (buf, endfor_end, strlen (endfor_end)); } /* generate an UNLESS statment */ void bash_unless (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for unless'\nexit 99\n"; static char unless_start[] = "if [[ ! ( "; static char unless_end[] = " ) ]]\nthen\n"; static char ex_start[] = "if ! "; static char ex_end[] = "\nthen\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else if (str[0] == '|') { str[0] = ' '; buffer_add (buf, ex_start, strlen (ex_start)); buffer_add (buf, str, len); buffer_add (buf, ex_end, strlen (ex_end)); } else { buffer_add (buf, unless_start, strlen (unless_start)); buffer_add (buf, str, len); buffer_add (buf, unless_end, strlen (unless_end)); } } /* generate an ELUN statment */ void bash_elun (buffer_t * buf, char *str, size_t len) { static char err_msg[] = "echo 'error: missing expression for elun'\nexit 99\n"; static char elun_start[] = "elif [[ ! ( "; static char elun_end[] = " ) ]]\nthen\n"; static char ex_start[] = "elif ! "; static char ex_end[] = "\nthen\n"; if (len == 0) { buffer_add (buf, err_msg, strlen (err_msg)); } else if (str[0] == '|') { str[0] = ' '; buffer_add (buf, ex_start, strlen (ex_start)); buffer_add (buf, str, len); buffer_add (buf, ex_end, strlen (ex_end)); } else { buffer_add (buf, elun_start, strlen (elun_start)); buffer_add (buf, str, len); buffer_add (buf, elun_end, strlen (elun_end)); } } /* generate an UNELSE statment */ void bash_unelse (buffer_t * buf, char *str, size_t len) { static char unelse_start[] = "else"; static char unelse_start2[] = "else #"; static char unelse_end[] = "\n"; if (len == 0) { buffer_add (buf, unelse_start, strlen (unelse_start)); } else { buffer_add (buf, unelse_start2, strlen (unelse_start2)); buffer_add (buf, str, len); } buffer_add (buf, unelse_end, strlen (unelse_end)); } /* generate a ENDUNLESS statment */ void bash_endunless (buffer_t * buf, char *str, size_t len) { static char endunless_start[] = "fi"; static char endunless_start2[] = "fi #"; static char endunless_end[] = "\n"; if (len == 0) { buffer_add (buf, endunless_start, strlen (endunless_start)); } else { buffer_add (buf, endunless_start2, strlen (endunless_start2)); buffer_add (buf, str, len); } buffer_add (buf, endunless_end, strlen (endunless_end)); } #endif void bash_doscript (buffer_t * script, char *name) { static char postfix[] = "\nexit\n"; /* dump the script to the subshell */ write (subshell_pipe[PARENT_OUT], script->data, script->ptr - script->data); /* write the postfix */ write (subshell_pipe[PARENT_OUT], postfix, strlen (postfix)); return; }