diff options
Diffstat (limited to 'updater')
-rw-r--r-- | updater/Android.mk | 10 | ||||
-rw-r--r-- | updater/blockimg.c | 254 | ||||
-rw-r--r-- | updater/install.c | 172 |
3 files changed, 339 insertions, 97 deletions
diff --git a/updater/Android.mk b/updater/Android.mk index c73cdc083..ff02a33b0 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -34,6 +34,16 @@ LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz LOCAL_STATIC_LIBRARIES += libmincrypt libbz LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc LOCAL_STATIC_LIBRARIES += libselinux +tune2fs_static_libraries := \ + libext2_com_err \ + libext2_blkid \ + libext2_quota \ + libext2_uuid_static \ + libext2_e2p \ + libext2fs +LOCAL_STATIC_LIBRARIES += libtune2fs $(tune2fs_static_libraries) + +LOCAL_C_INCLUDES += external/e2fsprogs/misc LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. # Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function diff --git a/updater/blockimg.c b/updater/blockimg.c index c3319c973..302689313 100644 --- a/updater/blockimg.c +++ b/updater/blockimg.c @@ -61,7 +61,7 @@ static RangeSet* parse_range(char* text) { RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int)); if (out == NULL) { - fprintf(stderr, "failed to allocate range of %lu bytes\n", + fprintf(stderr, "failed to allocate range of %zu bytes\n", sizeof(RangeSet) + num * sizeof(int)); exit(1); } @@ -245,6 +245,133 @@ static void* unzip_new_data(void* cookie) { return NULL; } +// Do a source/target load for move/bsdiff/imgdiff in version 1. +// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect +// to parse the remainder of the string as: +// +// <src_range> <tgt_range> +// +// The source range is loaded into the provided buffer, reallocating +// it to make it larger if necessary. The target ranges are returned +// in *tgt, if tgt is non-NULL. + +static void LoadSrcTgtVersion1(char* wordsave, RangeSet** tgt, int* src_blocks, + uint8_t** buffer, size_t* buffer_alloc, int fd) { + char* word; + + word = strtok_r(NULL, " ", &wordsave); + RangeSet* src = parse_range(word); + + if (tgt != NULL) { + word = strtok_r(NULL, " ", &wordsave); + *tgt = parse_range(word); + } + + allocate(src->size * BLOCKSIZE, buffer, buffer_alloc); + size_t p = 0; + int i; + for (i = 0; i < src->count; ++i) { + check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET); + size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE; + readblock(fd, *buffer+p, sz); + p += sz; + } + + *src_blocks = src->size; + free(src); +} + +static void MoveRange(uint8_t* dest, RangeSet* locs, const uint8_t* source) { + // source contains packed data, which we want to move to the + // locations given in *locs in the dest buffer. source and dest + // may be the same buffer. + + int start = locs->size; + int i; + for (i = locs->count-1; i >= 0; --i) { + int blocks = locs->pos[i*2+1] - locs->pos[i*2]; + start -= blocks; + memmove(dest + (locs->pos[i*2] * BLOCKSIZE), source + (start * BLOCKSIZE), + blocks * BLOCKSIZE); + } +} + +// Do a source/target load for move/bsdiff/imgdiff in version 2. +// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect +// to parse the remainder of the string as one of: +// +// <tgt_range> <src_block_count> <src_range> +// (loads data from source image only) +// +// <tgt_range> <src_block_count> - <[stash_id:stash_range] ...> +// (loads data from stashes only) +// +// <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...> +// (loads data from both source image and stashes) +// +// On return, buffer is filled with the loaded source data (rearranged +// and combined with stashed data as necessary). buffer may be +// reallocated if needed to accommodate the source data. *tgt is the +// target RangeSet. Any stashes required are taken from stash_table +// and free()'d after being used. + +static void LoadSrcTgtVersion2(char* wordsave, RangeSet** tgt, int* src_blocks, + uint8_t** buffer, size_t* buffer_alloc, int fd, + uint8_t** stash_table) { + char* word; + + if (tgt != NULL) { + word = strtok_r(NULL, " ", &wordsave); + *tgt = parse_range(word); + } + + word = strtok_r(NULL, " ", &wordsave); + *src_blocks = strtol(word, NULL, 0); + + allocate(*src_blocks * BLOCKSIZE, buffer, buffer_alloc); + + word = strtok_r(NULL, " ", &wordsave); + if (word[0] == '-' && word[1] == '\0') { + // no source ranges, only stashes + } else { + RangeSet* src = parse_range(word); + + size_t p = 0; + int i; + for (i = 0; i < src->count; ++i) { + check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET); + size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE; + readblock(fd, *buffer+p, sz); + p += sz; + } + free(src); + + word = strtok_r(NULL, " ", &wordsave); + if (word == NULL) { + // no stashes, only source range + return; + } + + RangeSet* locs = parse_range(word); + MoveRange(*buffer, locs, *buffer); + } + + while ((word = strtok_r(NULL, " ", &wordsave)) != NULL) { + // Each word is a an index into the stash table, a colon, and + // then a rangeset describing where in the source block that + // stashed data should go. + char* colonsave = NULL; + char* colon = strtok_r(word, ":", &colonsave); + int stash_id = strtol(colon, NULL, 0); + colon = strtok_r(NULL, ":", &colonsave); + RangeSet* locs = parse_range(colon); + MoveRange(*buffer, locs, stash_table[stash_id]); + free(stash_table[stash_id]); + stash_table[stash_id] = NULL; + free(locs); + } +} + // args: // - block device (or file) to modify in-place // - transfer list (blob) @@ -311,23 +438,33 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] // new [rangeset] // - fill the blocks with data read from the new_data file // - // bsdiff patchstart patchlen [src rangeset] [tgt rangeset] - // imgdiff patchstart patchlen [src rangeset] [tgt rangeset] - // - read the source blocks, apply a patch, write result to - // target blocks. bsdiff or imgdiff specifies the type of - // patch. - // - // move [src rangeset] [tgt rangeset] - // - copy data from source blocks to target blocks (no patch - // needed; rangesets are the same size) - // // erase [rangeset] // - mark the given blocks as empty // + // move <...> + // bsdiff <patchstart> <patchlen> <...> + // imgdiff <patchstart> <patchlen> <...> + // - read the source blocks, apply a patch (or not in the + // case of move), write result to target blocks. bsdiff or + // imgdiff specifies the type of patch; move means no patch + // at all. + // + // The format of <...> differs between versions 1 and 2; + // see the LoadSrcTgtVersion{1,2}() functions for a + // description of what's expected. + // + // stash <stash_id> <src_range> + // - (version 2 only) load the given source range and stash + // the data in the given slot of the stash table. + // // The creator of the transfer list will guarantee that no block // is read (ie, used as the source for a patch or move) after it // has been written. // + // In version 2, the creator will guarantee that a given stash is + // loaded (with a stash command) before it's used in a + // move/bsdiff/imgdiff command. + // // Within one command the source and target ranges may overlap so // in general we need to read the entire source into memory before // writing anything to the target blocks. @@ -379,12 +516,18 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] line = strtok_r(transfer_list, "\n", &linesave); + int version; // first line in transfer list is the version number; currently // there's only version 1. - if (strcmp(line, "1") != 0) { + if (strcmp(line, "1") == 0) { + version = 1; + } else if (strcmp(line, "2") == 0) { + version = 2; + } else { ErrorAbort(state, "unexpected transfer list version [%s]\n", line); goto done; } + printf("blockimg version is %d\n", version); // second line in transfer list is the total number of blocks we // expect to write. @@ -394,33 +537,49 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] if (total_blocks == 0) ++total_blocks; int blocks_so_far = 0; + uint8_t** stash_table = NULL; + if (version >= 2) { + // Next line is how many stash entries are needed simultaneously. + line = strtok_r(NULL, "\n", &linesave); + int stash_entries = strtol(line, NULL, 0); + + stash_table = (uint8_t**) calloc(stash_entries, sizeof(uint8_t*)); + if (stash_table == NULL) { + fprintf(stderr, "failed to allocate %d-entry stash table\n", stash_entries); + exit(1); + } + + // Next line is the maximum number of blocks that will be + // stashed simultaneously. This could be used to verify that + // enough memory or scratch disk space is available. + line = strtok_r(NULL, "\n", &linesave); + int stash_max_blocks = strtol(line, NULL, 0); + } + uint8_t* buffer = NULL; size_t buffer_alloc = 0; // third and subsequent lines are all individual transfer commands. for (line = strtok_r(NULL, "\n", &linesave); line; line = strtok_r(NULL, "\n", &linesave)) { + char* style; style = strtok_r(line, " ", &wordsave); if (strcmp("move", style) == 0) { - word = strtok_r(NULL, " ", &wordsave); - RangeSet* src = parse_range(word); - word = strtok_r(NULL, " ", &wordsave); - RangeSet* tgt = parse_range(word); + RangeSet* tgt; + int src_blocks; + if (version == 1) { + LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks, + &buffer, &buffer_alloc, fd); + } else if (version == 2) { + LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks, + &buffer, &buffer_alloc, fd, stash_table); + } - printf(" moving %d blocks\n", src->size); + printf(" moving %d blocks\n", src_blocks); - allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc); size_t p = 0; - for (i = 0; i < src->count; ++i) { - check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET); - size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE; - readblock(fd, buffer+p, sz); - p += sz; - } - - p = 0; for (i = 0; i < tgt->count; ++i) { check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET); size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE; @@ -432,9 +591,20 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks); fflush(cmd_pipe); - free(src); free(tgt); + } else if (strcmp("stash", style) == 0) { + word = strtok_r(NULL, " ", &wordsave); + int stash_id = strtol(word, NULL, 0); + int src_blocks; + size_t stash_alloc = 0; + + // Even though the "stash" style only appears in version + // 2, the version 1 source loader happens to do exactly + // what we want to read data into the stash_table. + LoadSrcTgtVersion1(wordsave, NULL, &src_blocks, + stash_table + stash_id, &stash_alloc, fd); + } else if (strcmp("zero", style) == 0 || (DEBUG_ERASE && strcmp("erase", style) == 0)) { word = strtok_r(NULL, " ", &wordsave); @@ -493,23 +663,18 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] word = strtok_r(NULL, " ", &wordsave); size_t patch_len = strtoul(word, NULL, 0); - word = strtok_r(NULL, " ", &wordsave); - RangeSet* src = parse_range(word); - word = strtok_r(NULL, " ", &wordsave); - RangeSet* tgt = parse_range(word); - - printf(" patching %d blocks to %d\n", src->size, tgt->size); - - // Read the source into memory. - allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc); - size_t p = 0; - for (i = 0; i < src->count; ++i) { - check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET); - size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE; - readblock(fd, buffer+p, sz); - p += sz; + RangeSet* tgt; + int src_blocks; + if (version == 1) { + LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks, + &buffer, &buffer_alloc, fd); + } else if (version == 2) { + LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks, + &buffer, &buffer_alloc, fd, stash_table); } + printf(" patching %d blocks to %d\n", src_blocks, tgt->size); + Value patch_value; patch_value.type = VAL_BLOB; patch_value.size = patch_len; @@ -523,11 +688,11 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET); if (style[0] == 'i') { // imgdiff - ApplyImagePatch(buffer, src->size * BLOCKSIZE, + ApplyImagePatch(buffer, src_blocks * BLOCKSIZE, &patch_value, &RangeSinkWrite, &rss, NULL, NULL); } else { - ApplyBSDiffPatch(buffer, src->size * BLOCKSIZE, + ApplyBSDiffPatch(buffer, src_blocks * BLOCKSIZE, &patch_value, 0, &RangeSinkWrite, &rss, NULL); } @@ -541,7 +706,6 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks); fflush(cmd_pipe); - free(src); free(tgt); } else if (!DEBUG_ERASE && strcmp("erase", style) == 0) { struct stat st; diff --git a/updater/install.c b/updater/install.c index dad0d08c9..2b2ffb0c5 100644 --- a/updater/install.c +++ b/updater/install.c @@ -46,12 +46,33 @@ #include "mtdutils/mtdutils.h" #include "updater.h" #include "install.h" +#include "tune2fs.h" #ifdef USE_EXT4 #include "make_ext4fs.h" #include "wipe.h" #endif +void uiPrint(State* state, char* buffer) { + char* line = strtok(buffer, "\n"); + UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); + while (line) { + fprintf(ui->cmd_pipe, "ui_print %s\n", line); + line = strtok(NULL, "\n"); + } + fprintf(ui->cmd_pipe, "ui_print\n"); +} + +__attribute__((__format__(printf, 2, 3))) __nonnull((2)) +void uiPrintf(State* state, const char* format, ...) { + char error_msg[1024]; + va_list ap; + va_start(ap, format); + vsnprintf(error_msg, sizeof(error_msg), format, ap); + va_end(ap); + uiPrint(state, error_msg); +} + // Take a sha-1 digest and return it as a newly-allocated hex string. char* PrintSha1(const uint8_t* digest) { char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1); @@ -71,16 +92,27 @@ char* PrintSha1(const uint8_t* digest) { // fs_type="ext4" partition_type="EMMC" location=device Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; - if (argc != 4) { - return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc); + if (argc != 4 && argc != 5) { + return ErrorAbort(state, "%s() expects 4-5 args, got %d", name, argc); } char* fs_type; char* partition_type; char* location; char* mount_point; - if (ReadArgs(state, argv, 4, &fs_type, &partition_type, + char* mount_options; + bool has_mount_options; + if (argc == 5) { + has_mount_options = true; + if (ReadArgs(state, argv, 5, &fs_type, &partition_type, + &location, &mount_point, &mount_options) < 0) { + return NULL; + } + } else { + has_mount_options = false; + if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &mount_point) < 0) { - return NULL; + return NULL; + } } if (strlen(fs_type) == 0) { @@ -120,13 +152,13 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { const MtdPartition* mtd; mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { - printf("%s: no mtd partition named \"%s\"", + uiPrintf(state, "%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) { - printf("mtd mount of %s failed: %s\n", + uiPrintf(state, "mtd mount of %s failed: %s\n", location, strerror(errno)); result = strdup(""); goto done; @@ -134,8 +166,9 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { result = mount_point; } else { if (mount(location, mount_point, fs_type, - MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { - printf("%s: failed to mount %s at %s: %s\n", + MS_NOATIME | MS_NODEV | MS_NODIRATIME, + has_mount_options ? mount_options : "") < 0) { + uiPrintf(state, "%s: failed to mount %s at %s: %s\n", name, location, mount_point, strerror(errno)); result = strdup(""); } else { @@ -148,6 +181,7 @@ done: free(partition_type); free(location); if (result != mount_point) free(mount_point); + if (has_mount_options) free(mount_options); return StringValue(result); } @@ -198,10 +232,14 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { scan_mounted_volumes(); const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); if (vol == NULL) { - printf("unmount of %s failed; no such volume\n", mount_point); + uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point); result = strdup(""); } else { - unmount_mounted_volume(vol); + int ret = unmount_mounted_volume(vol); + if (ret != 0) { + uiPrintf(state, "unmount of %s failed (%d): %s\n", + mount_point, ret, strerror(errno)); + } result = mount_point; } @@ -358,6 +396,9 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { if (make_parents(dst_name) != 0) { ErrorAbort(state, "Creating parent of %s failed, error %s", dst_name, strerror(errno)); + } else if (access(dst_name, F_OK) == 0 && access(src_name, F_OK) != 0) { + // File was already moved + result = dst_name; } else if (rename(src_name, dst_name) != 0) { ErrorAbort(state, "Rename of %s to %s failed, error %s", src_name, dst_name, strerror(errno)); @@ -630,7 +671,7 @@ struct perm_parsed_args { uint64_t capabilities; }; -static struct perm_parsed_args ParsePermArgs(int argc, char** args) { +static struct perm_parsed_args ParsePermArgs(State * state, int argc, char** args) { int i; struct perm_parsed_args parsed; int bad = 0; @@ -645,7 +686,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.uid = uid; parsed.has_uid = true; } else { - printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); bad++; } continue; @@ -656,7 +697,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.gid = gid; parsed.has_gid = true; } else { - printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); bad++; } continue; @@ -667,7 +708,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.mode = mode; parsed.has_mode = true; } else { - printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); bad++; } continue; @@ -678,7 +719,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.dmode = mode; parsed.has_dmode = true; } else { - printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); bad++; } continue; @@ -689,7 +730,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.fmode = mode; parsed.has_fmode = true; } else { - printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); bad++; } continue; @@ -700,7 +741,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.capabilities = capabilities; parsed.has_capabilities = true; } else { - printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); bad++; } continue; @@ -710,7 +751,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { parsed.selabel = args[i+1]; parsed.has_selabel = true; } else { - printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); bad++; } continue; @@ -727,71 +768,71 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) { } static int ApplyParsedPerms( + State * state, const char* filename, const struct stat *statptr, struct perm_parsed_args parsed) { int bad = 0; + if (parsed.has_selabel) { + if (lsetfilecon(filename, parsed.selabel) != 0) { + uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", + filename, parsed.selabel, strerror(errno)); + bad++; + } + } + /* ignore symlinks */ if (S_ISLNK(statptr->st_mode)) { - return 0; + return bad; } if (parsed.has_uid) { if (chown(filename, parsed.uid, -1) < 0) { - printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", - filename, parsed.uid, strerror(errno)); + uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n", + filename, parsed.uid, strerror(errno)); bad++; } } if (parsed.has_gid) { if (chown(filename, -1, parsed.gid) < 0) { - printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n", - filename, parsed.gid, strerror(errno)); + uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n", + filename, parsed.gid, strerror(errno)); bad++; } } if (parsed.has_mode) { if (chmod(filename, parsed.mode) < 0) { - printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", - filename, parsed.mode, strerror(errno)); + uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.mode, strerror(errno)); bad++; } } if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { if (chmod(filename, parsed.dmode) < 0) { - printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", - filename, parsed.dmode, strerror(errno)); + uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.dmode, strerror(errno)); bad++; } } if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { if (chmod(filename, parsed.fmode) < 0) { - printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.fmode, strerror(errno)); bad++; } } - if (parsed.has_selabel) { - // TODO: Don't silently ignore ENOTSUP - if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) { - printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", - filename, parsed.selabel, strerror(errno)); - bad++; - } - } - if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { if (parsed.capabilities == 0) { if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { // Report failure unless it's ENODATA (attribute not set) - printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", + uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", filename, parsed.capabilities, strerror(errno)); bad++; } @@ -804,8 +845,8 @@ static int ApplyParsedPerms( cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32); cap_data.data[1].inheritable = 0; if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { - printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", - filename, parsed.capabilities, strerror(errno)); + uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); bad++; } } @@ -817,10 +858,11 @@ static int ApplyParsedPerms( // nftw doesn't allow us to pass along context, so we need to use // global variables. *sigh* static struct perm_parsed_args recursive_parsed_args; +static State* recursive_state; static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr, int fileflags, struct FTW *pfwt) { - return ApplyParsedPerms(filename, statptr, recursive_parsed_args); + return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args); } static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -845,14 +887,16 @@ static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv goto done; } - struct perm_parsed_args parsed = ParsePermArgs(argc, args); + struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); if (recursive) { recursive_parsed_args = parsed; + recursive_state = state; bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); + recursive_state = NULL; } else { - bad += ApplyParsedPerms(args[0], &sb, parsed); + bad += ApplyParsedPerms(state, args[0], &sb, parsed); } done: @@ -1224,15 +1268,7 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { } free(args); buffer[size] = '\0'; - - char* line = strtok(buffer, "\n"); - while (line) { - fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, - "ui_print %s\n", line); - line = strtok(NULL, "\n"); - } - fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n"); - + uiPrint(state, buffer); return StringValue(buffer); } @@ -1504,6 +1540,37 @@ Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(strdup("t")); } +Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc == 0) { + return ErrorAbort(state, "%s() expects args, got %d", name, argc); + } + + char** args = ReadVarArgs(state, argc, argv); + if (args == NULL) { + return ErrorAbort(state, "%s() could not read args", name); + } + + int i; + char** args2 = malloc(sizeof(char*) * (argc+1)); + // Tune2fs expects the program name as its args[0] + args2[0] = strdup(name); + for (i = 0; i < argc; ++i) { + args2[i + 1] = args[i]; + } + int result = tune2fs_main(argc + 1, args2); + for (i = 0; i < argc; ++i) { + free(args[i]); + } + free(args); + + free(args2[0]); + free(args2); + if (result != 0) { + return ErrorAbort(state, "%s() returned error code %d", name, result); + } + return StringValue(strdup("t")); +} + void RegisterInstallFunctions() { RegisterFunction("mount", MountFn); RegisterFunction("is_mounted", IsMountedFn); @@ -1554,4 +1621,5 @@ void RegisterInstallFunctions() { RegisterFunction("set_stage", SetStageFn); RegisterFunction("enable_reboot", EnableRebootFn); + RegisterFunction("tune2fs", Tune2FsFn); } |