summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ball <nullspoon@oper.io>2020-12-28 22:10:32 -0700
committerAaron Ball <nullspoon@oper.io>2020-12-29 21:28:22 -0700
commitc407d6fa52aa5e579dd7e42e0b161111a8e31032 (patch)
tree532401f86c88a6fdca4f4ea0f102bdecb9f8fd56
parent1e223470ee80c794f2330e5a80145fd5a0dfb504 (diff)
downloadoper.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.
-rw-r--r--posts/librem5-no-wifi.rst8
-rw-r--r--src/common.c20
-rw-r--r--src/common.h3
-rw-r--r--src/j2.c100
-rw-r--r--src/j2.h5
-rw-r--r--src/main.c2
6 files changed, 101 insertions, 37 deletions
diff --git a/posts/librem5-no-wifi.rst b/posts/librem5-no-wifi.rst
index 2803404..bba7cbf 100644
--- a/posts/librem5-no-wifi.rst
+++ b/posts/librem5-no-wifi.rst
@@ -22,10 +22,12 @@ the phone with a SIM card, it would have retrieved the time from the cell
network or perhaps NTP and it would not have been an issue. However, I booted
it with no SIM card plugged in, so it had no way to know the date.
-To fix this, you can copy pasta this command in the terminal, replacing the
-date provided here with the actual date and time::
+To fix this, you can copy pasta this command in the terminal. It is updated on
+page load, so it should work as-is.
- sudo date -s "2020-12-27 12:00"
+.. code-block:: sh
+
+ sudo date -s "{{ shell date '+%F %T %Z' }}"
You don't need to get that accurate to the second, or even the minute or hour
to make things work. The NTP service should be able to adjust it slowly in the
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
diff --git a/src/j2.c b/src/j2.c
index 05fe442..b636c77 100644
--- a/src/j2.c
+++ b/src/j2.c
@@ -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);
diff --git a/src/j2.h b/src/j2.h
index 3e958d3..c08f9ec 100644
--- a/src/j2.h
+++ b/src/j2.h
@@ -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
diff --git a/src/main.c b/src/main.c
index 0e608f6..297ea96 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);

Generated by cgit