diff options
author | Aaron Ball <nullspoon@oper.io> | 2020-12-28 22:10:32 -0700 |
---|---|---|
committer | Aaron Ball <nullspoon@oper.io> | 2020-12-29 21:28:22 -0700 |
commit | c407d6fa52aa5e579dd7e42e0b161111a8e31032 (patch) | |
tree | 532401f86c88a6fdca4f4ea0f102bdecb9f8fd56 /src | |
parent | 1e223470ee80c794f2330e5a80145fd5a0dfb504 (diff) | |
download | oper.io-c407d6fa52aa5e579dd7e42e0b161111a8e31032.tar.gz oper.io-c407d6fa52aa5e579dd7e42e0b161111a8e31032.tar.xz |
j2:Add support for inline shell directiveimplement-runsh
This allows for render-time shell command input to the output document.
This also simplifies the j2_readvar function to make it handle input
line by line rather than as a pure stream, character by character, which
had incredibly complex logic and was very brittle. The new method is
more durable, though is a bit less efficient due to reprocessing the
string, though it no longer seeks back and forth.
Add j2_strstr function and better protect against buffer overflow
This also updates the librem 5 no wifi post to print the current date
and time at pageload.
Diffstat (limited to 'src')
-rw-r--r-- | src/common.c | 20 | ||||
-rw-r--r-- | src/common.h | 3 | ||||
-rw-r--r-- | src/j2.c | 100 | ||||
-rw-r--r-- | src/j2.h | 5 | ||||
-rw-r--r-- | src/main.c | 2 |
5 files changed, 96 insertions, 34 deletions
diff --git a/src/common.c b/src/common.c index 1891d78..db33bc0 100644 --- a/src/common.c +++ b/src/common.c @@ -75,3 +75,23 @@ int html_read_title(char* path, char* out) { return -1; } + +char* runsh(char* cmd) { + char buf[2048] = {'\0'}; + char* out = malloc(1); + FILE* fd = NULL; + unsigned long len = 0; + + fd = popen(cmd, "r"); + while(fgets(buf, 2048, fd) != NULL) { + len += strlen(buf); + out = realloc(out, len + 1); + strcat(out, buf); + } + pclose(fd); + + if(out[len - 1] == '\n') + out[len-1] = '\0'; + return out; +} + diff --git a/src/common.h b/src/common.h index aca549d..03529dd 100644 --- a/src/common.h +++ b/src/common.h @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <stdio.h> +#include <stdlib.h> #include <string.h> #ifndef _common_h @@ -29,4 +30,6 @@ int file_exists(char*); int html_read_title(char*, char*); +char* runsh(char*); + #endif @@ -18,30 +18,47 @@ #include "j2.h" -int j2_readvar(FILE* fd, char* buf) { - char c; - int i = 0; - fpos_t startpos; +char* j2_strstr(char* line) { + char* start; + char* end; - fgetpos(fd, &startpos); - //long seekstart = SEEK_CUR; + start = strstr(line, "{{ "); + if(start == NULL) + return NULL; + //start += 3; // Advance past the '{{ ' - if((c = fgetc(fd)) != '{') { - fsetpos(fd, &startpos); - return -1; - } - if(fgetc(fd) != ' ') { - fsetpos(fd, &startpos); - return -1; - } + // Check for the var close to ensure a complete definition is present + end = strstr(start, " }}"); - while((c = fgetc(fd)) != ' ') { - buf[i] = c; - i++; - } + // Incorrectly formatted, early return null + if(end == NULL) + return NULL; + + return start; +} + + +char* j2_readvar(char* line, char* buf, int maxlen) { + char* start = NULL; + char* end = NULL; - buf[i] = '\0'; - return 1; + start = j2_strstr(line); + if(start == NULL) + return NULL; + start += 3; + + // Because of how j2_strstr works, this will always work if start is not null + end = strstr(start, " }}"); + + // Only copy up to maxlen to avoid buffer overflows + if(end - start > maxlen) { + strncpy(buf, start, maxlen); + buf[maxlen] = '\0'; + } else { + strncpy(buf, start, end - start); + buf[end - start] = '\0'; + } + return end + 3; } @@ -50,23 +67,42 @@ int j2_readvar(FILE* fd, char* buf) { * matching environment variables. */ int j2_cat(char* path) { - char buf[512] = {'\0'}; - char c; + char line[J2_MAXLINE] = {'\0'}; + char buf[J2_MAXBUF] = {'\0'}; FILE* fd = fopen(path, "r"); + char* value = NULL; + char* varstart = NULL; + char* varend = NULL; - while((c = fgetc(fd)) != EOF) { - if(c == '{') { - if(j2_readvar(fd, buf) == -1) { - printf("{%s", buf); - continue; - } + while(fgets(line, J2_MAXLINE, fd) != NULL) { + varstart = j2_strstr(line); - printf("%s", getenv(buf)); - fgetc(fd); - fgetc(fd); + if(!varstart) { + printf(line); continue; } - printf("%c", c); + varend = j2_readvar(varstart, buf, J2_MAXBUF); + + // Break the beginning of the string and the beginning of the variable + // (this overwrites the first { that opens the variable def) + *varstart = '\0'; + // Because of the inserted null byte, this will print from byte 0 to there + printf("%s", line); + + // Execute the variable directive and print the output + if(strncmp(buf, "shell ", 6) == 0) { + // Execute the provided shell command and print that + value = runsh(&buf[6]); + printf("%s", value); + free(value); + } else { + // Print the referenced environment variable + value = getenv(buf); + printf("%s", value); + } + + // varend points to after the final }} of the variable def + printf("%s", varend); } fclose(fd); @@ -18,9 +18,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "common.h" -int j2_readvar(FILE*, char*); +#define J2_MAXLINE 4096 +#define J2_MAXBUF 1024 +char* j2_readvar(char*, char*, int); /** * Reads a jinja file and cats the output, interpolating variables, values from @@ -83,7 +83,7 @@ int main(int argc, char* argv[], char* envp[]) { setenv("PAGE_TITLE", title, 1); j2_cat(header); - catfile(path); + j2_cat(path); j2_cat(footer); fflush(stdout); |