mirror of
				https://github.com/meizu-m86/twrp_multirom_m86
				synced 2025-11-04 06:15:41 +08:00 
			
		
		
		
	Allow recovery to return error codes
Write error code, cause code, and retry count into last_install. So we can have more information about the reason of a failed OTA. Example of new last_install: @/cache/recovery/block.map package name 0 install result retry: 1 retry count (new) error: 30 error code (new) cause: 12 error cause (new) Details in: go/android-ota-errorcode Bug: 28471955 Change-Id: I00e7153c821e7355c1be81a86c7f228108f3dc37
This commit is contained in:
		@@ -113,7 +113,7 @@ apply_from_adb(RecoveryUI* ui_, bool* wipe_cache, const char* install_file) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false);
 | 
			
		||||
        result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false, 0);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,8 @@ LOCAL_YACCFLAGS := -v
 | 
			
		||||
LOCAL_CPPFLAGS += -Wno-unused-parameter
 | 
			
		||||
LOCAL_CPPFLAGS += -Wno-deprecated-register
 | 
			
		||||
LOCAL_CLANG := true
 | 
			
		||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
 | 
			
		||||
LOCAL_STATIC_LIBRARIES += libbase
 | 
			
		||||
 | 
			
		||||
include $(BUILD_HOST_EXECUTABLE)
 | 
			
		||||
 | 
			
		||||
@@ -36,5 +38,7 @@ LOCAL_CPPFLAGS := -Wno-unused-parameter
 | 
			
		||||
LOCAL_CPPFLAGS += -Wno-deprecated-register
 | 
			
		||||
LOCAL_MODULE := libedify
 | 
			
		||||
LOCAL_CLANG := true
 | 
			
		||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
 | 
			
		||||
LOCAL_STATIC_LIBRARIES += libbase
 | 
			
		||||
 | 
			
		||||
include $(BUILD_STATIC_LIBRARY)
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,11 @@
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include <android-base/stringprintf.h>
 | 
			
		||||
#include <android-base/strings.h>
 | 
			
		||||
 | 
			
		||||
#include "expr.h"
 | 
			
		||||
 | 
			
		||||
// Functions should:
 | 
			
		||||
@@ -36,7 +41,7 @@ char* Evaluate(State* state, Expr* expr) {
 | 
			
		||||
    Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
 | 
			
		||||
    if (v == NULL) return NULL;
 | 
			
		||||
    if (v->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "expecting string, got value type %d", v->type);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type);
 | 
			
		||||
        FreeValue(v);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
@@ -493,15 +498,29 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    return args;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Use printf-style arguments to compose an error message to put into
 | 
			
		||||
// *state.  Returns NULL.
 | 
			
		||||
Value* ErrorAbort(State* state, const char* format, ...) {
 | 
			
		||||
    char* buffer = reinterpret_cast<char*>(malloc(4096));
 | 
			
		||||
    va_list v;
 | 
			
		||||
    va_start(v, format);
 | 
			
		||||
    vsnprintf(buffer, 4096, format, v);
 | 
			
		||||
    va_end(v);
 | 
			
		||||
static void ErrorAbortV(State* state, const char* format, va_list ap) {
 | 
			
		||||
    std::string buffer;
 | 
			
		||||
    android::base::StringAppendV(&buffer, format, ap);
 | 
			
		||||
    free(state->errmsg);
 | 
			
		||||
    state->errmsg = buffer;
 | 
			
		||||
    return NULL;
 | 
			
		||||
    state->errmsg = strdup(buffer.c_str());
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Use printf-style arguments to compose an error message to put into
 | 
			
		||||
// *state.  Returns nullptr.
 | 
			
		||||
Value* ErrorAbort(State* state, const char* format, ...) {
 | 
			
		||||
    va_list ap;
 | 
			
		||||
    va_start(ap, format);
 | 
			
		||||
    ErrorAbortV(state, format, ap);
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
 | 
			
		||||
    va_list ap;
 | 
			
		||||
    va_start(ap, format);
 | 
			
		||||
    ErrorAbortV(state, format, ap);
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
    state->cause_code = cause_code;
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								edify/expr.h
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								edify/expr.h
									
									
									
									
									
								
							@@ -19,6 +19,7 @@
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "error_code.h"
 | 
			
		||||
#include "yydefs.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_STRING_LEN 1024
 | 
			
		||||
@@ -39,6 +40,15 @@ typedef struct {
 | 
			
		||||
    // Should be NULL initially, will be either NULL or a malloc'd
 | 
			
		||||
    // pointer after Evaluate() returns.
 | 
			
		||||
    char* errmsg;
 | 
			
		||||
 | 
			
		||||
    // error code indicates the type of failure (e.g. failure to update system image)
 | 
			
		||||
    // during the OTA process.
 | 
			
		||||
    ErrorCode error_code = kNoError;
 | 
			
		||||
 | 
			
		||||
    // cause code provides more detailed reason of an OTA failure (e.g. fsync error)
 | 
			
		||||
    // in addition to the error code.
 | 
			
		||||
    CauseCode cause_code = kNoCause;
 | 
			
		||||
 | 
			
		||||
} State;
 | 
			
		||||
 | 
			
		||||
#define VAL_STRING  1  // data will be NULL-terminated; size doesn't count null
 | 
			
		||||
@@ -152,7 +162,13 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]);
 | 
			
		||||
 | 
			
		||||
// Use printf-style arguments to compose an error message to put into
 | 
			
		||||
// *state.  Returns NULL.
 | 
			
		||||
Value* ErrorAbort(State* state, const char* format, ...) __attribute__((format(printf, 2, 3)));
 | 
			
		||||
Value* ErrorAbort(State* state, const char* format, ...)
 | 
			
		||||
    __attribute__((format(printf, 2, 3), deprecated));
 | 
			
		||||
 | 
			
		||||
// ErrorAbort has an optional (but recommended) argument 'cause_code'. If the cause code
 | 
			
		||||
// is set, it will be logged into last_install and provides reason of OTA failures.
 | 
			
		||||
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...)
 | 
			
		||||
    __attribute__((format(printf, 3, 4)));
 | 
			
		||||
 | 
			
		||||
// Wrap a string into a Value, taking ownership of the string.
 | 
			
		||||
Value* StringValue(char* str);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								error_code.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								error_code.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 The Android Open Source Project
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _ERROR_CODE_H_
 | 
			
		||||
#define _ERROR_CODE_H_
 | 
			
		||||
 | 
			
		||||
enum ErrorCode {
 | 
			
		||||
    kNoError = -1,
 | 
			
		||||
    kLowBattery = 20,
 | 
			
		||||
    kZipVerificationFailure,
 | 
			
		||||
    kZipOpenFailure
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum CauseCode {
 | 
			
		||||
    kNoCause = -1,
 | 
			
		||||
    kArgsParsingFailure = 100,
 | 
			
		||||
    kStashCreationFailure,
 | 
			
		||||
    kFileOpenFailure,
 | 
			
		||||
    kLseekFailure,
 | 
			
		||||
    kFreadFailure,
 | 
			
		||||
    kFwriteFailure,
 | 
			
		||||
    kFsyncFailure,
 | 
			
		||||
    kLibfecFailure,
 | 
			
		||||
    kFileGetPropFailure,
 | 
			
		||||
    kFileRenameFailure,
 | 
			
		||||
    kSymlinkFailure,
 | 
			
		||||
    kSetMetadataFailure,
 | 
			
		||||
    kTune2FsFailure,
 | 
			
		||||
    kRebootFailure,
 | 
			
		||||
    kVendorFailure = 200
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										13
									
								
								install.cpp
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								install.cpp
									
									
									
									
									
								
							@@ -27,7 +27,11 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <android-base/stringprintf.h>
 | 
			
		||||
#include <android-base/strings.h>
 | 
			
		||||
 | 
			
		||||
#include "common.h"
 | 
			
		||||
#include "error_code.h"
 | 
			
		||||
#include "install.h"
 | 
			
		||||
#include "minui/minui.h"
 | 
			
		||||
#include "minzip/SysUtil.h"
 | 
			
		||||
@@ -253,6 +257,8 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
 | 
			
		||||
    ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err);
 | 
			
		||||
    if (err != VERIFY_SUCCESS) {
 | 
			
		||||
        LOGE("signature verification failed\n");
 | 
			
		||||
        log_buffer.push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
 | 
			
		||||
 | 
			
		||||
        sysReleaseMap(&map);
 | 
			
		||||
        return INSTALL_CORRUPT;
 | 
			
		||||
    }
 | 
			
		||||
@@ -262,6 +268,8 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
 | 
			
		||||
    err = mzOpenZipArchive(map.addr, map.length, &zip);
 | 
			
		||||
    if (err != 0) {
 | 
			
		||||
        LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
 | 
			
		||||
        log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
 | 
			
		||||
 | 
			
		||||
        sysReleaseMap(&map);
 | 
			
		||||
        return INSTALL_CORRUPT;
 | 
			
		||||
    }
 | 
			
		||||
@@ -280,7 +288,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
install_package(const char* path, bool* wipe_cache, const char* install_file,
 | 
			
		||||
                bool needs_mount)
 | 
			
		||||
                bool needs_mount, int retry_count)
 | 
			
		||||
{
 | 
			
		||||
    modified_flash = true;
 | 
			
		||||
    auto start = std::chrono::system_clock::now();
 | 
			
		||||
@@ -300,13 +308,14 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
 | 
			
		||||
    } else {
 | 
			
		||||
        result = really_install_package(path, wipe_cache, needs_mount, log_buffer);
 | 
			
		||||
    }
 | 
			
		||||
    if (install_log) {
 | 
			
		||||
    if (install_log != nullptr) {
 | 
			
		||||
        fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
 | 
			
		||||
        fputc('\n', install_log);
 | 
			
		||||
        std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
 | 
			
		||||
        int count = static_cast<int>(duration.count());
 | 
			
		||||
        // Report the time spent to apply OTA update in seconds.
 | 
			
		||||
        fprintf(install_log, "time_total: %d\n", count);
 | 
			
		||||
        fprintf(install_log, "retry: %d\n", retry_count);
 | 
			
		||||
 | 
			
		||||
        for (const auto& s : log_buffer) {
 | 
			
		||||
            fprintf(install_log, "%s\n", s.c_str());
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@ enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SK
 | 
			
		||||
// Install the package specified by root_path.  If INSTALL_SUCCESS is
 | 
			
		||||
// returned and *wipe_cache is true on exit, caller should wipe the
 | 
			
		||||
// cache partition.
 | 
			
		||||
int install_package(const char* root_path, bool* wipe_cache,
 | 
			
		||||
                    const char* install_file, bool needs_mount);
 | 
			
		||||
int install_package(const char* root_path, bool* wipe_cache, const char* install_file,
 | 
			
		||||
                    bool needs_mount, int retry_count);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								recovery.cpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								recovery.cpp
									
									
									
									
									
								
							@@ -50,6 +50,7 @@
 | 
			
		||||
#include "bootloader.h"
 | 
			
		||||
#include "common.h"
 | 
			
		||||
#include "device.h"
 | 
			
		||||
#include "error_code.h"
 | 
			
		||||
#include "fuse_sdcard_provider.h"
 | 
			
		||||
#include "fuse_sideload.h"
 | 
			
		||||
#include "install.h"
 | 
			
		||||
@@ -1000,7 +1001,7 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
 | 
			
		||||
                                 TEMPORARY_INSTALL_FILE, false);
 | 
			
		||||
                                 TEMPORARY_INSTALL_FILE, false, 0/*retry_count*/);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1455,10 +1456,21 @@ int main(int argc, char **argv) {
 | 
			
		||||
        if (!is_battery_ok()) {
 | 
			
		||||
            ui->Print("battery capacity is not enough for installing package, needed is %d%%\n",
 | 
			
		||||
                      BATTERY_OK_PERCENTAGE);
 | 
			
		||||
            // Log the error code to last_install when installation skips due to
 | 
			
		||||
            // low battery.
 | 
			
		||||
            FILE* install_log = fopen_path(LAST_INSTALL_FILE, "w");
 | 
			
		||||
            if (install_log != nullptr) {
 | 
			
		||||
                fprintf(install_log, "%s\n", update_package);
 | 
			
		||||
                fprintf(install_log, "0\n");
 | 
			
		||||
                fprintf(install_log, "error: %d\n", kLowBattery);
 | 
			
		||||
                fclose(install_log);
 | 
			
		||||
            } else {
 | 
			
		||||
                LOGE("failed to open last_install: %s\n", strerror(errno));
 | 
			
		||||
            }
 | 
			
		||||
            status = INSTALL_SKIPPED;
 | 
			
		||||
        } else {
 | 
			
		||||
            status = install_package(update_package, &should_wipe_cache,
 | 
			
		||||
                                     TEMPORARY_INSTALL_FILE, true);
 | 
			
		||||
                                     TEMPORARY_INSTALL_FILE, true, retry_count);
 | 
			
		||||
            if (status == INSTALL_SUCCESS && should_wipe_cache) {
 | 
			
		||||
                wipe_cache(false, device);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@
 | 
			
		||||
 | 
			
		||||
#include "applypatch/applypatch.h"
 | 
			
		||||
#include "edify/expr.h"
 | 
			
		||||
#include "error_code.h"
 | 
			
		||||
#include "install.h"
 | 
			
		||||
#include "openssl/sha.h"
 | 
			
		||||
#include "minzip/Hash.h"
 | 
			
		||||
@@ -68,6 +69,7 @@ struct RangeSet {
 | 
			
		||||
    std::vector<size_t> pos;  // Actual limit is INT_MAX.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static CauseCode failure_type = kNoCause;
 | 
			
		||||
static std::map<std::string, RangeSet> stash_map;
 | 
			
		||||
 | 
			
		||||
static void parse_range(const std::string& range_text, RangeSet& rs) {
 | 
			
		||||
@@ -145,6 +147,7 @@ static int read_all(int fd, uint8_t* data, size_t size) {
 | 
			
		||||
    while (so_far < size) {
 | 
			
		||||
        ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
 | 
			
		||||
        if (r == -1) {
 | 
			
		||||
            failure_type = kFreadFailure;
 | 
			
		||||
            fprintf(stderr, "read failed: %s\n", strerror(errno));
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
@@ -162,6 +165,7 @@ static int write_all(int fd, const uint8_t* data, size_t size) {
 | 
			
		||||
    while (written < size) {
 | 
			
		||||
        ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
 | 
			
		||||
        if (w == -1) {
 | 
			
		||||
            failure_type = kFwriteFailure;
 | 
			
		||||
            fprintf(stderr, "write failed: %s\n", strerror(errno));
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
@@ -178,6 +182,7 @@ static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
 | 
			
		||||
static bool check_lseek(int fd, off64_t offset, int whence) {
 | 
			
		||||
    off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
 | 
			
		||||
    if (rc == -1) {
 | 
			
		||||
        failure_type = kLseekFailure;
 | 
			
		||||
        fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -648,6 +653,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ota_fsync(fd) == -1) {
 | 
			
		||||
        failure_type = kFsyncFailure;
 | 
			
		||||
        fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
@@ -663,11 +669,13 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks
 | 
			
		||||
    unique_fd dfd_holder(dfd);
 | 
			
		||||
 | 
			
		||||
    if (dfd == -1) {
 | 
			
		||||
        failure_type = kFileOpenFailure;
 | 
			
		||||
        fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ota_fsync(dfd) == -1) {
 | 
			
		||||
        failure_type = kFsyncFailure;
 | 
			
		||||
        fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
@@ -696,19 +704,21 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s
 | 
			
		||||
    int res = stat(dirname.c_str(), &sb);
 | 
			
		||||
 | 
			
		||||
    if (res == -1 && errno != ENOENT) {
 | 
			
		||||
        ErrorAbort(state, "stat \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
 | 
			
		||||
        ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n",
 | 
			
		||||
                   dirname.c_str(), strerror(errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    } else if (res != 0) {
 | 
			
		||||
        fprintf(stderr, "creating stash %s\n", dirname.c_str());
 | 
			
		||||
        res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
 | 
			
		||||
 | 
			
		||||
        if (res != 0) {
 | 
			
		||||
            ErrorAbort(state, "mkdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
 | 
			
		||||
            ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n",
 | 
			
		||||
                       dirname.c_str(), strerror(errno));
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (CacheSizeCheck(maxblocks * BLOCKSIZE) != 0) {
 | 
			
		||||
            ErrorAbort(state, "not enough space for stash\n");
 | 
			
		||||
            ErrorAbort(state, kStashCreationFailure, "not enough space for stash\n");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -728,7 +738,8 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s
 | 
			
		||||
    size = maxblocks * BLOCKSIZE - size;
 | 
			
		||||
 | 
			
		||||
    if (size > 0 && CacheSizeCheck(size) != 0) {
 | 
			
		||||
        ErrorAbort(state, "not enough space for stash (%d more needed)\n", size);
 | 
			
		||||
        ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%d more needed)\n",
 | 
			
		||||
                   size);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1346,19 +1357,21 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
    std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue);
 | 
			
		||||
 | 
			
		||||
    if (blockdev_filename->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
 | 
			
		||||
                   name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
    if (transfer_list_value->type != VAL_BLOB) {
 | 
			
		||||
        ErrorAbort(state, "transfer_list argument to %s must be blob", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
    if (new_data_fn->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "new_data_fn argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
    if (patch_data_fn->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "patch_data_fn argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string",
 | 
			
		||||
                   name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1418,7 +1431,8 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
    const std::string transfer_list(transfer_list_value->data, transfer_list_value->size);
 | 
			
		||||
    std::vector<std::string> lines = android::base::Split(transfer_list, "\n");
 | 
			
		||||
    if (lines.size() < 2) {
 | 
			
		||||
        ErrorAbort(state, "too few lines in the transfer list [%zd]\n", lines.size());
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n",
 | 
			
		||||
                   lines.size());
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1433,7 +1447,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
    // Second line in transfer list is the total number of blocks we expect to write
 | 
			
		||||
    int total_blocks;
 | 
			
		||||
    if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) {
 | 
			
		||||
        ErrorAbort(state, "unexpected block count [%s]\n", lines[1].c_str());
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str());
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1444,7 +1458,8 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
    size_t start = 2;
 | 
			
		||||
    if (params.version >= 2) {
 | 
			
		||||
        if (lines.size() < 4) {
 | 
			
		||||
            ErrorAbort(state, "too few lines in the transfer list [%zu]\n", lines.size());
 | 
			
		||||
            ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n",
 | 
			
		||||
                       lines.size());
 | 
			
		||||
            return StringValue(strdup(""));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1454,7 +1469,8 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
        // Fourth line is the maximum number of blocks that will be stashed simultaneously
 | 
			
		||||
        int stash_max_blocks;
 | 
			
		||||
        if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) {
 | 
			
		||||
            ErrorAbort(state, "unexpected maximum stash blocks [%s]\n", lines[3].c_str());
 | 
			
		||||
            ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n",
 | 
			
		||||
                       lines[3].c_str());
 | 
			
		||||
            return StringValue(strdup(""));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1508,6 +1524,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
 | 
			
		||||
        if (params.canwrite) {
 | 
			
		||||
            if (ota_fsync(params.fd) == -1) {
 | 
			
		||||
                failure_type = kFsyncFailure;
 | 
			
		||||
                fprintf(stderr, "fsync failed: %s\n", strerror(errno));
 | 
			
		||||
                goto pbiudone;
 | 
			
		||||
            }
 | 
			
		||||
@@ -1542,6 +1559,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
 | 
			
		||||
 | 
			
		||||
pbiudone:
 | 
			
		||||
    if (ota_fsync(params.fd) == -1) {
 | 
			
		||||
        failure_type = kFsyncFailure;
 | 
			
		||||
        fprintf(stderr, "fsync failed: %s\n", strerror(errno));
 | 
			
		||||
    }
 | 
			
		||||
    // params.fd will be automatically closed because of the fd_holder above.
 | 
			
		||||
@@ -1552,6 +1570,10 @@ pbiudone:
 | 
			
		||||
        DeleteStash(params.stashbase);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (failure_type != kNoCause && state->cause_code == kNoCause) {
 | 
			
		||||
        state->cause_code = failure_type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return StringValue(rc == 0 ? strdup("t") : strdup(""));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1657,18 +1679,20 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[])
 | 
			
		||||
            FreeValue);
 | 
			
		||||
 | 
			
		||||
    if (blockdev_filename->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
 | 
			
		||||
                   name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
    if (ranges->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "ranges argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int fd = open(blockdev_filename->data, O_RDWR);
 | 
			
		||||
    unique_fd fd_holder(fd);
 | 
			
		||||
    if (fd < 0) {
 | 
			
		||||
        ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno));
 | 
			
		||||
        ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", blockdev_filename->data,
 | 
			
		||||
                   strerror(errno));
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1681,13 +1705,14 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[])
 | 
			
		||||
    std::vector<uint8_t> buffer(BLOCKSIZE);
 | 
			
		||||
    for (size_t i = 0; i < rs.count; ++i) {
 | 
			
		||||
        if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) {
 | 
			
		||||
            ErrorAbort(state, "failed to seek %s: %s", blockdev_filename->data, strerror(errno));
 | 
			
		||||
            ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data,
 | 
			
		||||
                       strerror(errno));
 | 
			
		||||
            return StringValue(strdup(""));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) {
 | 
			
		||||
            if (read_all(fd, buffer, BLOCKSIZE) == -1) {
 | 
			
		||||
                ErrorAbort(state, "failed to read %s: %s", blockdev_filename->data,
 | 
			
		||||
                ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data,
 | 
			
		||||
                        strerror(errno));
 | 
			
		||||
                return StringValue(strdup(""));
 | 
			
		||||
            }
 | 
			
		||||
@@ -1715,14 +1740,15 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[])
 | 
			
		||||
    std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue);
 | 
			
		||||
 | 
			
		||||
    if (filename->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "filename argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int fd = open(arg_filename->data, O_RDONLY);
 | 
			
		||||
    unique_fd fd_holder(fd);
 | 
			
		||||
    if (fd == -1) {
 | 
			
		||||
        ErrorAbort(state, "open \"%s\" failed: %s", arg_filename->data, strerror(errno));
 | 
			
		||||
        ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data,
 | 
			
		||||
                   strerror(errno));
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1730,7 +1756,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[])
 | 
			
		||||
    std::vector<uint8_t> block0_buffer(BLOCKSIZE);
 | 
			
		||||
 | 
			
		||||
    if (ReadBlocks(blk0, block0_buffer, fd) == -1) {
 | 
			
		||||
        ErrorAbort(state, "failed to read %s: %s", arg_filename->data,
 | 
			
		||||
        ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data,
 | 
			
		||||
                strerror(errno));
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
@@ -1766,11 +1792,11 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[
 | 
			
		||||
    std::unique_ptr<Value, decltype(&FreeValue)> ranges(arg_ranges, FreeValue);
 | 
			
		||||
 | 
			
		||||
    if (filename->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "filename argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
    if (ranges->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "ranges argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1781,19 +1807,20 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[
 | 
			
		||||
    fec::io fh(filename->data, O_RDWR);
 | 
			
		||||
 | 
			
		||||
    if (!fh) {
 | 
			
		||||
        ErrorAbort(state, "fec_open \"%s\" failed: %s", filename->data, strerror(errno));
 | 
			
		||||
        ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data,
 | 
			
		||||
                   strerror(errno));
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!fh.has_ecc() || !fh.has_verity()) {
 | 
			
		||||
        ErrorAbort(state, "unable to use metadata to correct errors");
 | 
			
		||||
        ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors");
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fec_status status;
 | 
			
		||||
 | 
			
		||||
    if (!fh.get_status(status)) {
 | 
			
		||||
        ErrorAbort(state, "failed to read FEC status");
 | 
			
		||||
        ErrorAbort(state, kLibfecFailure, "failed to read FEC status");
 | 
			
		||||
        return StringValue(strdup(""));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1810,8 +1837,8 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) {
 | 
			
		||||
                ErrorAbort(state, "failed to recover %s (block %zu): %s", filename->data,
 | 
			
		||||
                    j, strerror(errno));
 | 
			
		||||
                ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s",
 | 
			
		||||
                           filename->data, j, strerror(errno));
 | 
			
		||||
                return StringValue(strdup(""));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,10 +47,11 @@
 | 
			
		||||
#include "cutils/misc.h"
 | 
			
		||||
#include "cutils/properties.h"
 | 
			
		||||
#include "edify/expr.h"
 | 
			
		||||
#include "openssl/sha.h"
 | 
			
		||||
#include "error_code.h"
 | 
			
		||||
#include "minzip/DirUtil.h"
 | 
			
		||||
#include "mtdutils/mounts.h"
 | 
			
		||||
#include "mtdutils/mtdutils.h"
 | 
			
		||||
#include "openssl/sha.h"
 | 
			
		||||
#include "ota_io.h"
 | 
			
		||||
#include "updater.h"
 | 
			
		||||
#include "install.h"
 | 
			
		||||
@@ -113,7 +114,7 @@ char* PrintSha1(const uint8_t* digest) {
 | 
			
		||||
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    char* result = NULL;
 | 
			
		||||
    if (argc != 4 && argc != 5) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 4-5 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* fs_type;
 | 
			
		||||
    char* partition_type;
 | 
			
		||||
@@ -136,20 +137,21 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strlen(fs_type) == 0) {
 | 
			
		||||
        ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(partition_type) == 0) {
 | 
			
		||||
        ErrorAbort(state, "partition_type argument to %s() can't be empty",
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty",
 | 
			
		||||
                   name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(location) == 0) {
 | 
			
		||||
        ErrorAbort(state, "location argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(mount_point) == 0) {
 | 
			
		||||
        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty",
 | 
			
		||||
                   name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -212,14 +214,14 @@ done:
 | 
			
		||||
Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    char* result = NULL;
 | 
			
		||||
    if (argc != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* mount_point;
 | 
			
		||||
    if (ReadArgs(state, argv, 1, &mount_point) < 0) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(mount_point) == 0) {
 | 
			
		||||
        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to unmount() can't be empty");
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -242,14 +244,14 @@ done:
 | 
			
		||||
Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    char* result = NULL;
 | 
			
		||||
    if (argc != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* mount_point;
 | 
			
		||||
    if (ReadArgs(state, argv, 1, &mount_point) < 0) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(mount_point) == 0) {
 | 
			
		||||
        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to unmount() can't be empty");
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -300,7 +302,7 @@ static int exec_cmd(const char* path, char* const argv[]) {
 | 
			
		||||
Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    char* result = NULL;
 | 
			
		||||
    if (argc != 5) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* fs_type;
 | 
			
		||||
    char* partition_type;
 | 
			
		||||
@@ -313,21 +315,22 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strlen(fs_type) == 0) {
 | 
			
		||||
        ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(partition_type) == 0) {
 | 
			
		||||
        ErrorAbort(state, "partition_type argument to %s() can't be empty",
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty",
 | 
			
		||||
                   name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(location) == 0) {
 | 
			
		||||
        ErrorAbort(state, "location argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strlen(mount_point) == 0) {
 | 
			
		||||
        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty",
 | 
			
		||||
                   name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -402,7 +405,7 @@ done:
 | 
			
		||||
Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    char* result = NULL;
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char* src_name;
 | 
			
		||||
@@ -412,21 +415,21 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(src_name) == 0) {
 | 
			
		||||
        ErrorAbort(state, "src_name argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (strlen(dst_name) == 0) {
 | 
			
		||||
        ErrorAbort(state, "dst_name argument to %s() can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (make_parents(dst_name) != 0) {
 | 
			
		||||
        ErrorAbort(state, "Creating parent of %s failed, error %s",
 | 
			
		||||
        ErrorAbort(state, kFileRenameFailure, "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",
 | 
			
		||||
        ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s",
 | 
			
		||||
          src_name, dst_name, strerror(errno));
 | 
			
		||||
    } else {
 | 
			
		||||
        result = dst_name;
 | 
			
		||||
@@ -469,7 +472,7 @@ Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* frac_str;
 | 
			
		||||
    char* sec_str;
 | 
			
		||||
@@ -490,7 +493,7 @@ Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* frac_str;
 | 
			
		||||
    if (ReadArgs(state, argv, 1, &frac_str) < 0) {
 | 
			
		||||
@@ -509,7 +512,7 @@ Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
Value* PackageExtractDirFn(const char* name, State* state,
 | 
			
		||||
                          int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* zip_path;
 | 
			
		||||
    char* dest_path;
 | 
			
		||||
@@ -537,7 +540,7 @@ Value* PackageExtractDirFn(const char* name, State* state,
 | 
			
		||||
Value* PackageExtractFileFn(const char* name, State* state,
 | 
			
		||||
                           int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc < 1 || argc > 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d",
 | 
			
		||||
                          name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    bool success = false;
 | 
			
		||||
@@ -645,7 +648,7 @@ static int make_parents(char* name) {
 | 
			
		||||
//    unlinks any previously existing src1, src2, etc before creating symlinks.
 | 
			
		||||
Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc == 0) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1+ args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* target;
 | 
			
		||||
    target = Evaluate(state, argv[0]);
 | 
			
		||||
@@ -681,7 +684,7 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    }
 | 
			
		||||
    free(srcs);
 | 
			
		||||
    if (bad) {
 | 
			
		||||
        return ErrorAbort(state, "%s: some symlinks failed", name);
 | 
			
		||||
        return ErrorAbort(state, kSymlinkFailure, "%s: some symlinks failed", name);
 | 
			
		||||
    }
 | 
			
		||||
    return StringValue(strdup(""));
 | 
			
		||||
}
 | 
			
		||||
@@ -905,14 +908,16 @@ static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv
 | 
			
		||||
    bool recursive = (strcmp(name, "set_metadata_recursive") == 0);
 | 
			
		||||
 | 
			
		||||
    if ((argc % 2) != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects an odd number of arguments, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure,
 | 
			
		||||
                          "%s() expects an odd number of arguments, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char** args = ReadVarArgs(state, argc, argv);
 | 
			
		||||
    if (args == NULL) return NULL;
 | 
			
		||||
 | 
			
		||||
    if (lstat(args[0], &sb) == -1) {
 | 
			
		||||
        result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno));
 | 
			
		||||
        result = ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s",
 | 
			
		||||
                            name, args[0], strerror(errno));
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -941,7 +946,7 @@ done:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bad > 0) {
 | 
			
		||||
        return ErrorAbort(state, "%s: some changes failed", name);
 | 
			
		||||
        return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return StringValue(strdup(""));
 | 
			
		||||
@@ -949,7 +954,7 @@ done:
 | 
			
		||||
 | 
			
		||||
Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* key = Evaluate(state, argv[0]);
 | 
			
		||||
    if (key == NULL) return NULL;
 | 
			
		||||
@@ -978,32 +983,36 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
    struct stat st;
 | 
			
		||||
    if (stat(filename, &st) < 0) {
 | 
			
		||||
        ErrorAbort(state, "%s: failed to stat \"%s\": %s", name, filename, strerror(errno));
 | 
			
		||||
        ErrorAbort(state, kFileGetPropFailure, "%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);
 | 
			
		||||
        ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %d)", filename, name,
 | 
			
		||||
                   MAX_FILE_GETPROP_SIZE);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buffer = reinterpret_cast<char*>(malloc(st.st_size+1));
 | 
			
		||||
    if (buffer == NULL) {
 | 
			
		||||
        ErrorAbort(state, "%s: failed to alloc %lld bytes", name, (long long)st.st_size+1);
 | 
			
		||||
        ErrorAbort(state, kFileGetPropFailure, "%s: failed to alloc %lld bytes", name,
 | 
			
		||||
                   (long long)st.st_size+1);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FILE* f;
 | 
			
		||||
    f = fopen(filename, "rb");
 | 
			
		||||
    if (f == NULL) {
 | 
			
		||||
        ErrorAbort(state, "%s: failed to open %s: %s", name, filename, strerror(errno));
 | 
			
		||||
        ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, filename,
 | 
			
		||||
                   strerror(errno));
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ota_fread(buffer, 1, st.st_size, f) != static_cast<size_t>(st.st_size)) {
 | 
			
		||||
        ErrorAbort(state, "%s: failed to read %lld bytes from %s",
 | 
			
		||||
        ErrorAbort(state, kFreadFailure, "%s: failed to read %lld bytes from %s",
 | 
			
		||||
                   name, (long long)st.st_size+1, filename);
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        goto done;
 | 
			
		||||
@@ -1069,16 +1078,16 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
    char* partition = NULL;
 | 
			
		||||
    if (partition_value->type != VAL_STRING) {
 | 
			
		||||
        ErrorAbort(state, "partition argument to %s must be string", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "partition argument to %s must be string", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    partition = partition_value->data;
 | 
			
		||||
    if (strlen(partition) == 0) {
 | 
			
		||||
        ErrorAbort(state, "partition argument to %s can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "partition argument to %s can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
    if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
 | 
			
		||||
        ErrorAbort(state, "file argument to %s can't be empty", name);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "file argument to %s can't be empty", name);
 | 
			
		||||
        goto done;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1159,7 +1168,8 @@ Value* ApplyPatchSpaceFn(const char* name, State* state,
 | 
			
		||||
 | 
			
		||||
    size_t bytes;
 | 
			
		||||
    if (!android::base::ParseUint(bytes_str, &bytes)) {
 | 
			
		||||
        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n", name, bytes_str);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count\n\n",
 | 
			
		||||
                   name, bytes_str);
 | 
			
		||||
        free(bytes_str);
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1171,9 +1181,8 @@ Value* ApplyPatchSpaceFn(const char* name, State* state,
 | 
			
		||||
 | 
			
		||||
Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc < 6 || (argc % 2) == 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s(): expected at least 6 args and an "
 | 
			
		||||
                                 "even number, got %d",
 | 
			
		||||
                          name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 6 args and an "
 | 
			
		||||
                                 "even number, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char* source_filename;
 | 
			
		||||
@@ -1187,7 +1196,8 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
    size_t target_size;
 | 
			
		||||
    if (!android::base::ParseUint(target_size_str, &target_size)) {
 | 
			
		||||
        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count", name, target_size_str);
 | 
			
		||||
        ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count",
 | 
			
		||||
                   name, target_size_str);
 | 
			
		||||
        free(source_filename);
 | 
			
		||||
        free(target_filename);
 | 
			
		||||
        free(target_sha1);
 | 
			
		||||
@@ -1211,11 +1221,11 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < patchcount; ++i) {
 | 
			
		||||
        if (patch_shas[i]->type != VAL_STRING) {
 | 
			
		||||
            ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
 | 
			
		||||
            ErrorAbort(state, kArgsParsingFailure, "%s(): sha-1 #%d is not string", name, i);
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
        if (patches[i]->type != VAL_BLOB) {
 | 
			
		||||
            ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
 | 
			
		||||
            ErrorAbort(state, kArgsParsingFailure, "%s(): patch #%d is not blob", name, i);
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1238,7 +1248,7 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
Value* ApplyPatchCheckFn(const char* name, State* state,
 | 
			
		||||
                         int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc < 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 1 arg, got %d",
 | 
			
		||||
                          name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1283,7 +1293,7 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 0) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
 | 
			
		||||
    return StringValue(strdup("t"));
 | 
			
		||||
@@ -1291,7 +1301,7 @@ Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc < 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects at least 1 arg", name);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name);
 | 
			
		||||
    }
 | 
			
		||||
    char** args = ReadVarArgs(state, argc, argv);
 | 
			
		||||
    if (args == NULL) {
 | 
			
		||||
@@ -1345,7 +1355,7 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
//
 | 
			
		||||
Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc < 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects at least 1 arg", name);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc, argv), free);
 | 
			
		||||
@@ -1393,7 +1403,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
// is actually a FileContents*).
 | 
			
		||||
Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    char* filename;
 | 
			
		||||
    if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
 | 
			
		||||
@@ -1429,7 +1439,7 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
// partition.
 | 
			
		||||
Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char* filename;
 | 
			
		||||
@@ -1455,7 +1465,7 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
    sleep(5);
 | 
			
		||||
    free(property);
 | 
			
		||||
    ErrorAbort(state, "%s() failed to reboot", name);
 | 
			
		||||
    ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1471,7 +1481,7 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
// bytes.
 | 
			
		||||
Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char* filename;
 | 
			
		||||
@@ -1501,7 +1511,7 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
// is the block device for the misc partition.
 | 
			
		||||
Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 1) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char* filename;
 | 
			
		||||
@@ -1519,7 +1529,7 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 2) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char* filename;
 | 
			
		||||
@@ -1541,7 +1551,7 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[])
 | 
			
		||||
 | 
			
		||||
Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc != 0) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc);
 | 
			
		||||
    }
 | 
			
		||||
    UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
 | 
			
		||||
    fprintf(ui->cmd_pipe, "enable_reboot\n");
 | 
			
		||||
@@ -1550,12 +1560,12 @@ Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
 | 
			
		||||
Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    if (argc == 0) {
 | 
			
		||||
        return ErrorAbort(state, "%s() expects args, got %d", name, argc);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%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);
 | 
			
		||||
        return ErrorAbort(state, kArgsParsingFailure, "%s() could not read args", name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char** args2 = reinterpret_cast<char**>(malloc(sizeof(char*) * (argc+1)));
 | 
			
		||||
@@ -1573,7 +1583,8 @@ Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) {
 | 
			
		||||
    free(args2[0]);
 | 
			
		||||
    free(args2);
 | 
			
		||||
    if (result != 0) {
 | 
			
		||||
        return ErrorAbort(state, "%s() returned error code %d", name, result);
 | 
			
		||||
        return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d",
 | 
			
		||||
                          name, result);
 | 
			
		||||
    }
 | 
			
		||||
    return StringValue(strdup("t"));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -156,11 +156,28 @@ int main(int argc, char** argv) {
 | 
			
		||||
            printf("script aborted: %s\n", state.errmsg);
 | 
			
		||||
            char* line = strtok(state.errmsg, "\n");
 | 
			
		||||
            while (line) {
 | 
			
		||||
                // Parse the error code in abort message.
 | 
			
		||||
                // Example: "E30: This package is for bullhead devices."
 | 
			
		||||
                if (*line == 'E') {
 | 
			
		||||
                    if (sscanf(line, "E%u: ", &state.error_code) != 1) {
 | 
			
		||||
                         printf("Failed to parse error code: [%s]\n", line);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                fprintf(cmd_pipe, "ui_print %s\n", line);
 | 
			
		||||
                line = strtok(NULL, "\n");
 | 
			
		||||
            }
 | 
			
		||||
            fprintf(cmd_pipe, "ui_print\n");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (state.error_code != kNoError) {
 | 
			
		||||
            fprintf(cmd_pipe, "log error: %d\n", state.error_code);
 | 
			
		||||
            // Cause code should provide additional information about the abort;
 | 
			
		||||
            // report only when an error exists.
 | 
			
		||||
            if (state.cause_code != kNoCause) {
 | 
			
		||||
                fprintf(cmd_pipe, "log cause: %d\n", state.cause_code);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        free(state.errmsg);
 | 
			
		||||
        return 7;
 | 
			
		||||
    } else {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user