From 47cace98369f60df2351a65801c8065bb7f9dbf0 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 18 Jun 2009 10:11:50 -0700 Subject: [PATCH] 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. --- edify/expr.c | 13 ++++++ edify/expr.h | 4 ++ updater/install.c | 111 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 117 insertions(+), 11 deletions(-) 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 @@ char** ReadVarArgs(State* state, int argc, Expr* argv[]) { } 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 @@ int ReadArgs(State* state, Expr* argv[], int count, ...); // 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 @@ char* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } +// 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 @@ void RegisterInstallFunctions() { RegisterFunction("set_perm_recursive", SetPermFn); RegisterFunction("getprop", GetPropFn); + RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("write_raw_image", WriteRawImageFn); RegisterFunction("write_firmware_image", WriteFirmwareImageFn);