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.
This commit is contained in:
parent
fb2e3af3f9
commit
47cace9836
13
edify/expr.c
13
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user