cbsi/subshell.c

374 行
8.3 KiB
C

/**
* @PROJECT CGI Bash Shell Interface
* @COPYRIGHT See COPYING in the top level directory
* @FILE subshell.c
* @PURPOSE Subshell execution
* @DEVELOPERS Nathan Angelacos <nangel@users.sourceforge.net>
* Rafal Kupiec <belliash@asiotec.eu.org>
*/
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <getopt.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "common.h"
#include "buffer.h"
#include "error.h"
#include "subshell.h"
#include "cbsi.h"
char open_tag[3] = "<%";
char close_tag[3] = "%>";
const char* g_tag[] = {
"",
"",
":",
"@",
""
};
token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist) {
char* start;
char* end;
char* curpos;
char* endpos;
token_t* curtoken;
token_t* firsttoken;
curtoken = tokenlist;
firsttoken = tokenlist;
curpos = scriptbuf->buf + scriptbuf->curpos;
endpos = scriptbuf->buf + scriptbuf->size;
while(curpos < endpos) {
start = strstr(curpos, open_tag);
end = strstr(curpos, close_tag);
if(start && !end) {
die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]);
}
if((start > end) || (!start && end)) {
die_with_message(scriptbuf, end, g_err_msg[E_END_BEFORE_BEGIN], open_tag[1], open_tag[1]);
}
if(start && (strstr(start + 1, open_tag) && (strstr (start + 1, open_tag) < end)))
die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]);
if(end) {
curtoken = push_token_on_list(curtoken, scriptbuf, curpos, start - curpos);
if(firsttoken == NULL) {
firsttoken = curtoken;
}
curtoken = push_token_on_list(curtoken, scriptbuf, start, end - start);
if(firsttoken == NULL) {
firsttoken = curtoken;
}
curpos = end + 2;
} else {
curtoken = push_token_on_list(curtoken, scriptbuf, curpos, endpos - curpos);
if(firsttoken == NULL) {
firsttoken = curtoken;
}
curpos = endpos;
}
}
return firsttoken;
}
void free_script_list(script_t* script) {
script_t* next;
while(script) {
next = script->next;
if(script->name) {
free(script->name);
}
if(script->buf) {
free(script->buf);
}
free(script);
script = next;
}
}
void free_token_list(token_t* tokenlist) {
token_t* next;
while(tokenlist) {
next = tokenlist->next;
free(tokenlist);
tokenlist = next;
}
}
script_t* load_script(char* filename, script_t* scriptlist) {
script_t* scriptbuf;
int scriptfp;
struct stat filestat;
scriptfp = open(filename, O_NONBLOCK + O_RDONLY);
if(scriptfp == -1) {
die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], filename);
}
fstat(scriptfp, &filestat);
scriptbuf = (script_t *) xmalloc(sizeof (script_t));
scriptbuf->name = (char *) xmalloc(strlen (filename) + 1);
scriptbuf->buf = (char *) xmalloc(filestat.st_size + 1);
memset(scriptbuf->name, 0, strlen(filename) + 1);
memcpy(scriptbuf->name, filename, strlen(filename));
memset(scriptbuf->buf, 0, filestat.st_size + 1);
read(scriptfp, scriptbuf->buf, filestat.st_size);
scriptbuf->size = filestat.st_size;
scriptbuf->uid = filestat.st_uid;
scriptbuf->gid = filestat.st_gid;
scriptbuf->curpos = 0;
scriptbuf->next = NULL;
if(scriptlist != NULL) {
while(scriptlist->next) {
scriptlist = scriptlist->next;
}
scriptlist->next = scriptbuf;
}
if(memcmp(scriptbuf->buf, "#!", 2) == 0) {
while((scriptbuf->curpos < scriptbuf->size) && ((char) scriptbuf->buf[scriptbuf->curpos] != '\n')) {
(scriptbuf->curpos)++;
}
(scriptbuf->curpos)++;
}
close(scriptfp);
return scriptbuf;
}
void preprocess_token_list(token_t* tokenlist) {
script_t* newscript;
token_t* me;
char* cp;
me = tokenlist;
while(me) {
if(memcmp(me->buf, open_tag, 2)) {
me->tag = HTML;
} else {
me->tag = NOOP;
me->buf[me->len] = '\0';
cp = me->buf + 2;
if(memcmp(cp, g_tag[ECHO], 1) == 0) {
me->tag = ECHO;
me->buf = find_whitespace(me->buf);
me->len = strlen(me->buf);
} else if(memcmp(cp, g_tag[TRANSLATE], 1) == 0) {
me->tag = TRANSLATE;
me->buf = find_whitespace(me->buf);
me->len = strlen(me->buf);
}
if(isspace(*cp)) {
me->tag = RUN;
me->buf = cp;
}
if(me->tag == NOOP) {
die_with_message(me->script, cp, g_err_msg[E_NO_OP]);
}
me->len = strlen(me->buf);
}
me = me->next;
}
}
token_t* process_token_list(buffer_t* buf, token_t* token) {
char *c;
buffer_init(buf);
subshell_exec(buf, "\n");
while(token) {
switch(token->tag) {
case HTML:
c = token->buf;
while((c < (token->buf + token->len)) && (isspace(*c))) {
c++;
}
if(c != token->buf + token->len) {
subshell_echo (buf, token->buf, token->len);
}
break;
case RUN:
subshell_exec(buf, token->buf);
subshell_exec(buf, "\n");
break;
case ECHO:
subshell_eval(buf, token->buf, token->len);
break;
case TRANSLATE:
subshell_translate(buf, token->buf, token->len);
break;
default:
break;
}
token = token->next;
}
return token;
}
token_t* push_token_on_list(token_t* tokenlist, script_t* scriptbuf, char* start, size_t len) {
token_t* me;
token_t* next;
if(len == 0) {
return tokenlist;
}
me = (token_t*) xmalloc(sizeof(token_t));
if(tokenlist == NULL) {
next = NULL;
} else {
next = tokenlist->next;
tokenlist->next = me;
}
me->next = next;
me->script = scriptbuf;
me->buf = start;
me->len = len;
return me;
}
void subshell_destroy(void) {
int status;
waitpid(subshell_pid, &status, 0);
}
void subshell_doscript(buffer_t* script, char* name) {
static char postfix[] = "\nexit\n";
write(subshell_pipe[PARENT_OUT], script->data, script->ptr - script->data);
write(subshell_pipe[PARENT_OUT], postfix, strlen(postfix));
return;
}
void subshell_echo(buffer_t* buf, char* str, size_t len) {
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));
}
void subshell_eval(buffer_t* buf, char* str, size_t len) {
static char echo_start[] = "echo -n ";
static char echo_end[] = "\n";
if(len == 0) {
return;
}
str = trim(str);
if(!*str) {
return;
}
buffer_add(buf, echo_start, strlen(echo_start));
buffer_add(buf, str, len);
buffer_add(buf, echo_end, strlen(echo_end));
}
void subshell_exec(buffer_t* buf, char* str) {
buffer_add (buf, str, strlen (str));
return;
}
void subshell_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) {
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) {
av[19] = "\0";
count = 18;
}
while(count >= 0) {
av[count] = argv[count].string;
count--;
}
while(env) {
next = env->next;
putenv(env->buf);
env = next;
}
execv(argv[0].string, av);
free(argv);
die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
} else {
close(subshell_pipe[PARENT_IN]);
}
}
}
void subshell_translate(buffer_t* buf, char* str, size_t len) {
static char echo_start[] = "echo -n \"";
static char echo_end[] = "\"\n";
short hash;
lstr* i;
char* text = NULL;
if(len == 0) {
return;
}
str = trim(str);
if(!*str) {
return;
}
if(language != NULL && translations > 0) {
hash = generateHash(str);
i = ltable[hash];
while(text == NULL && i != NULL) {
if(strcmp(str, i->msgid) == 0) {
text = i->msgstr;
} else {
i = i->next;
}
}
}
if(text == NULL) {
text = str;
}
buffer_add(buf, echo_start, strlen(echo_start));
buffer_add(buf, text, strlen(text));
buffer_add(buf, echo_end, strlen(echo_end));
}