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:
		
							
								
								
									
										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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user