summaryrefslogtreecommitdiffstats
path: root/updater
diff options
context:
space:
mode:
Diffstat (limited to 'updater')
-rw-r--r--updater/Android.mk10
-rw-r--r--updater/blockimg.c254
-rw-r--r--updater/install.c172
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);
}