add file_getprop() to updater
Add a function to read a property from a ".prop"-formatted file
(key=value pairs, one per line, ignore # comment lines and blank
lines). Move ErrorAbort to the core of edify; it's not specific to
updater now that errors aren't stored in the app cookie.
diff --git a/edify/expr.c b/edify/expr.c
index f1c5555..72e5100 100644
--- a/edify/expr.c
+++ b/edify/expr.c
@@ -417,3 +417,16 @@
}
return args;
}
+
+// Use printf-style arguments to compose an error message to put into
+// *state. Returns NULL.
+char* ErrorAbort(State* state, char* format, ...) {
+ char* buffer = malloc(4096);
+ va_list v;
+ va_start(v, format);
+ vsnprintf(buffer, 4096, format, v);
+ va_end(v);
+ free(state->errmsg);
+ state->errmsg = buffer;
+ return NULL;
+}
diff --git a/edify/expr.h b/edify/expr.h
index 671b499..d2e7392 100644
--- a/edify/expr.h
+++ b/edify/expr.h
@@ -118,5 +118,9 @@
// strings it contains.
char** ReadVarArgs(State* state, int argc, Expr* argv[]);
+// Use printf-style arguments to compose an error message to put into
+// *state. Returns NULL.
+char* ErrorAbort(State* state, char* format, ...);
+
#endif // _EXPRESSION_H
diff --git a/updater/install.c b/updater/install.c
index 616cb2c..0bd0939 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -32,17 +32,6 @@
#include "mtdutils/mtdutils.h"
#include "updater.h"
-char* ErrorAbort(State* state, char* format, ...) {
- char* buffer = malloc(4096);
- va_list v;
- va_start(v, format);
- vsnprintf(buffer, 4096, format, v);
- va_end(v);
- free(state->errmsg);
- state->errmsg = buffer;
- return NULL;
-}
-
// mount(type, location, mount_point)
//
@@ -449,6 +438,105 @@
}
+// file_getprop(file, key)
+//
+// interprets 'file' as a getprop-style file (key=value pairs, one
+// per line, # comment lines and blank lines okay), and returns the value
+// for 'key' (or "" if it isn't defined).
+char* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
+ char* result = NULL;
+ char* buffer = NULL;
+ char* filename;
+ char* key;
+ if (ReadArgs(state, argv, 2, &filename, &key) < 0) {
+ return NULL;
+ }
+
+ struct stat st;
+ if (stat(filename, &st) < 0) {
+ ErrorAbort(state, "%s: failed to stat \"%s\": %s",
+ name, filename, strerror(errno));
+ goto done;
+ }
+
+#define MAX_FILE_GETPROP_SIZE 65536
+
+ if (st.st_size > MAX_FILE_GETPROP_SIZE) {
+ ErrorAbort(state, "%s too large for %s (max %d)",
+ filename, name, MAX_FILE_GETPROP_SIZE);
+ goto done;
+ }
+
+ buffer = malloc(st.st_size+1);
+ if (buffer == NULL) {
+ ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
+ goto done;
+ }
+
+ FILE* f = fopen(filename, "rb");
+ if (f == NULL) {
+ ErrorAbort(state, "%s: failed to open %s: %s",
+ name, filename, strerror(errno));
+ goto done;
+ }
+
+ if (fread(buffer, 1, st.st_size, f) != st.st_size) {
+ ErrorAbort(state, "%s: failed to read %d bytes from %s",
+ name, st.st_size+1, filename);
+ fclose(f);
+ goto done;
+ }
+ buffer[st.st_size] = '\0';
+
+ fclose(f);
+
+ char* line = strtok(buffer, "\n");
+ do {
+ // skip whitespace at start of line
+ while (*line && isspace(*line)) ++line;
+
+ // comment or blank line: skip to next line
+ if (*line == '\0' || *line == '#') continue;
+
+ char* equal = strchr(line, '=');
+ if (equal == NULL) {
+ ErrorAbort(state, "%s: malformed line \"%s\": %s not a prop file?",
+ name, line, filename);
+ goto done;
+ }
+
+ // trim whitespace between key and '='
+ char* key_end = equal-1;
+ while (key_end > line && isspace(*key_end)) --key_end;
+ key_end[1] = '\0';
+
+ // not the key we're looking for
+ if (strcmp(key, line) != 0) continue;
+
+ // skip whitespace after the '=' to the start of the value
+ char* val_start = equal+1;
+ while(*val_start && isspace(*val_start)) ++val_start;
+
+ // trim trailing whitespace
+ char* val_end = val_start + strlen(val_start)-1;
+ while (val_end > val_start && isspace(*val_end)) --val_end;
+ val_end[1] = '\0';
+
+ result = strdup(val_start);
+ break;
+
+ } while ((line = strtok(NULL, "\n")));
+
+ if (result == NULL) result = strdup("");
+
+ done:
+ free(filename);
+ free(key);
+ free(buffer);
+ return result;
+}
+
+
static bool write_raw_image_cb(const unsigned char* data,
int data_len, void* ctx) {
int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len);
@@ -670,6 +758,7 @@
RegisterFunction("set_perm_recursive", SetPermFn);
RegisterFunction("getprop", GetPropFn);
+ RegisterFunction("file_getprop", FileGetPropFn);
RegisterFunction("write_raw_image", WriteRawImageFn);
RegisterFunction("write_firmware_image", WriteFirmwareImageFn);