Merge "recovery: Add librecovery_updater_msm library"
This commit is contained in:
commit
51b3b4b1a8
|
@ -615,6 +615,9 @@ PRODUCT_PACKAGES += \
|
|||
# Flatland
|
||||
PRODUCT_PACKAGES += flatland
|
||||
|
||||
# MSM updater library
|
||||
PRODUCT_PACKAGES += librecovery_updater_msm
|
||||
|
||||
PRODUCT_COPY_FILES := \
|
||||
frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml \
|
||||
frameworks/native/data/etc/android.hardware.camera.front.xml:system/etc/permissions/android.hardware.camera.front.xml \
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
ifeq ($(TARGET_RECOVERY_UPDATER_LIBS),librecovery_updater_msm)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_C_INCLUDES := bootable/recovery \
|
||||
system/core/libsparse \
|
||||
$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
LOCAL_SRC_FILES := gpt-utils.c dec.c oem-updater.c
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
LOCAL_MODULE := librecovery_updater_msm
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
endif
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/qseecom.h>
|
||||
#include <linux/msm_ion.h>
|
||||
|
||||
/* Service IDs */
|
||||
#define SCM_SVC_SSD 0x07
|
||||
|
||||
/* Service specific command IDs */
|
||||
#define SSD_PARSE_MD_ID 0x06
|
||||
#define SSD_DECRYPT_IMG_FRAG_ID 0x07
|
||||
|
||||
/* SSD parsing status messages from TZ */
|
||||
#define SSD_PMD_ENCRYPTED 0
|
||||
#define SSD_PMD_NOT_ENCRYPTED 1
|
||||
#define SSD_PMD_PARSING_INCOMPLETE 6
|
||||
|
||||
#define SSD_HEADER_MIN_SIZE 128
|
||||
#define MULTIPLICATION_FACTOR 2
|
||||
|
||||
#define SMCMOD_DECRYPT_REQ_OP_METADATA 1
|
||||
#define SMCMOD_DECRYPT_REQ_OP_IMG_FRAG 2
|
||||
|
||||
struct smcmod_decrypt_req {
|
||||
uint32_t service_id; /* in */
|
||||
uint32_t command_id; /* in */
|
||||
uint32_t operation; /* in */
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t len;
|
||||
uint32_t ion_fd;
|
||||
} metadata;
|
||||
struct {
|
||||
uint32_t ctx_id;
|
||||
uint32_t last_frag;
|
||||
uint32_t frag_len;
|
||||
uint32_t ion_fd;
|
||||
uint32_t offset;
|
||||
} img_frag;
|
||||
} request;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t status;
|
||||
uint32_t ctx_id;
|
||||
uint32_t end_offset;
|
||||
} metadata;
|
||||
struct {
|
||||
uint32_t status;
|
||||
} img_frag;
|
||||
} response;
|
||||
};
|
||||
|
||||
#define SMCMOD_IOC_MAGIC 0x97
|
||||
#define SMCMOD_IOCTL_DECRYPT_CMD \
|
||||
_IOWR(SMCMOD_IOC_MAGIC, 37, struct smcmod_decrypt_req)
|
||||
|
||||
struct ion_buf_handle {
|
||||
unsigned char *buffer;
|
||||
uint32_t buffer_len;
|
||||
int ion_fd;
|
||||
int ifd_data_fd;
|
||||
struct ion_handle_data ion_alloc_handle;
|
||||
};
|
||||
|
||||
static int
|
||||
ion_memalloc(struct ion_buf_handle *buf, uint32_t size, uint32_t heap)
|
||||
{
|
||||
struct ion_allocation_data alloc_data;
|
||||
struct ion_fd_data fd_data;
|
||||
unsigned char *va;
|
||||
struct ion_handle_data handle_data;
|
||||
int ion_fd;
|
||||
int rc;
|
||||
|
||||
ion_fd = open("/dev/ion", O_RDONLY);
|
||||
if (ion_fd < 0) {
|
||||
fprintf(stderr, "Cannot open ION device (%s)\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
alloc_data.len = (size + 4095) & ~4095;
|
||||
alloc_data.align = 4096;
|
||||
|
||||
alloc_data.flags = 0;
|
||||
alloc_data.heap_mask = ION_HEAP(heap);
|
||||
|
||||
/* Set the buffers to be uncached */
|
||||
alloc_data.flags = 0;
|
||||
|
||||
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
|
||||
if (rc) {
|
||||
fprintf(stderr, "ION buffer allocation failed (%s)\n",
|
||||
strerror(errno));
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
if (alloc_data.handle) {
|
||||
fd_data.handle = alloc_data.handle;
|
||||
} else {
|
||||
fprintf(stderr, "ION alloc data returned NULL\n");
|
||||
rc = -1;
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
|
||||
if (rc) {
|
||||
fprintf(stderr, "ION map call failed(%s)\n", strerror(errno));
|
||||
goto ioctl_fail;
|
||||
}
|
||||
|
||||
va = mmap(NULL, alloc_data.len, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd_data.fd, 0);
|
||||
if (va == MAP_FAILED) {
|
||||
fprintf(stderr, "ION memory map failed (%s)\n", strerror(errno));
|
||||
rc = -1;
|
||||
goto map_fail;
|
||||
}
|
||||
|
||||
buf->ion_fd = ion_fd;
|
||||
buf->ifd_data_fd = fd_data.fd;
|
||||
buf->buffer = va;
|
||||
buf->ion_alloc_handle.handle = alloc_data.handle;
|
||||
buf->buffer_len = alloc_data.len;
|
||||
|
||||
memset(buf->buffer, 0, buf->buffer_len);
|
||||
return 0;
|
||||
|
||||
map_fail:
|
||||
ioctl_fail:
|
||||
handle_data.handle = alloc_data.handle;
|
||||
if (buf->ifd_data_fd)
|
||||
close(buf->ifd_data_fd);
|
||||
rc = ioctl(ion_fd, ION_IOC_FREE, &handle_data);
|
||||
if (rc)
|
||||
fprintf(stderr, "ION free failed (%s)\n", strerror(errno));
|
||||
alloc_fail:
|
||||
if (ion_fd >= 0)
|
||||
close(ion_fd);
|
||||
buf->ion_fd = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ion_memfree(struct ion_buf_handle *handle)
|
||||
{
|
||||
struct ion_handle_data handle_data;
|
||||
int ret;
|
||||
|
||||
ret = munmap(handle->buffer, (handle->buffer_len + 4095) & ~4095);
|
||||
if (ret)
|
||||
fprintf(stderr, "munmap failed (%s)\n", strerror(errno));
|
||||
|
||||
handle_data.handle = handle->ion_alloc_handle.handle;
|
||||
close(handle->ifd_data_fd);
|
||||
ret = ioctl(handle->ion_fd, ION_IOC_FREE, &handle_data);
|
||||
if (ret)
|
||||
fprintf(stderr, "ION free failed (%s)\n", strerror(errno));
|
||||
close(handle->ion_fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ion_buffer_clean_inval(struct ion_buf_handle *buf, uint32_t cmd)
|
||||
{
|
||||
struct ion_flush_data data;
|
||||
int rc;
|
||||
|
||||
data.fd = buf->ifd_data_fd;
|
||||
data.vaddr = buf->buffer;
|
||||
data.length = buf->buffer_len;
|
||||
data.offset = 0;
|
||||
data.handle = buf->ion_alloc_handle.handle;
|
||||
|
||||
rc = ioctl(buf->ion_fd, cmd, &data);
|
||||
if (rc < 0)
|
||||
fprintf(stderr, "clean_inval cache failed (%s)\n", strerror(errno));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int is_encrypted(int smcmod_fd, struct ion_buf_handle *buf,
|
||||
uint32_t len, uint32_t *ctx_id, uint32_t *end_offset)
|
||||
{
|
||||
struct smcmod_decrypt_req req;
|
||||
uint32_t status;
|
||||
int ret;
|
||||
|
||||
req.service_id = SCM_SVC_SSD;
|
||||
req.command_id = SSD_PARSE_MD_ID;
|
||||
req.operation = SMCMOD_DECRYPT_REQ_OP_METADATA;
|
||||
req.request.metadata.len =
|
||||
(len >= SSD_HEADER_MIN_SIZE) ? SSD_HEADER_MIN_SIZE : len;
|
||||
req.request.metadata.ion_fd = buf->ifd_data_fd;
|
||||
|
||||
do {
|
||||
ret = ioctl(smcmod_fd, SMCMOD_IOCTL_DECRYPT_CMD, &req);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "%s: ioctl ret=%d, %s\n", __func__, ret,
|
||||
strerror(errno));
|
||||
|
||||
status = req.response.metadata.status;
|
||||
|
||||
if (!ret && (status == SSD_PMD_PARSING_INCOMPLETE)) {
|
||||
req.request.metadata.len *= MULTIPLICATION_FACTOR;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (!ret) {
|
||||
if (status == SSD_PMD_ENCRYPTED) {
|
||||
*ctx_id = req.response.metadata.ctx_id;
|
||||
*end_offset = req.response.metadata.end_offset;
|
||||
ret = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Image is not encrypted (response status %d)\n",
|
||||
status);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s: call failed\n", __func__);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decrypt(int smcmod_fd, struct ion_buf_handle *buf, uint32_t len,
|
||||
uint32_t md_ctx, uint32_t offset)
|
||||
{
|
||||
struct smcmod_decrypt_req req;
|
||||
int ret;
|
||||
|
||||
req.service_id = SCM_SVC_SSD;
|
||||
req.command_id = SSD_DECRYPT_IMG_FRAG_ID;
|
||||
req.operation = SMCMOD_DECRYPT_REQ_OP_IMG_FRAG;
|
||||
req.request.img_frag.ctx_id = md_ctx;
|
||||
req.request.img_frag.last_frag = 1;
|
||||
req.request.img_frag.ion_fd = buf->ifd_data_fd;
|
||||
req.request.img_frag.frag_len = len - offset;
|
||||
req.request.img_frag.offset = offset;
|
||||
|
||||
ret = ioctl(smcmod_fd, SMCMOD_IOCTL_DECRYPT_CMD, &req);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "decrypt ioctl failed (%s)\n", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int save_file(const char *fname, unsigned char *buf, size_t len)
|
||||
{
|
||||
FILE *file;
|
||||
size_t written;
|
||||
|
||||
file = fopen(fname, "wb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open %s (%s)\n", fname, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
written = fwrite(buf, len, 1, file);
|
||||
if (written != 1) {
|
||||
fclose(file);
|
||||
fprintf(stderr, "Failed to write %s (%s)\n", fname, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
fflush(file);
|
||||
fclose(file);
|
||||
fprintf(stdout, "%s written %d bytes\n", fname, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int decrypt_image(const char *src_file, const char *dst_file)
|
||||
{
|
||||
int ret = -1;
|
||||
uint32_t md_ctx = 0, offset = 0;
|
||||
uint32_t fsize = 0;
|
||||
FILE *file = NULL;
|
||||
struct ion_buf_handle ionbuf;
|
||||
int smcmod_fd = -1;
|
||||
int qseecom_fd = -1;
|
||||
size_t read;
|
||||
|
||||
memset(&ionbuf, 0, sizeof(ionbuf));
|
||||
ionbuf.ion_fd = -1;
|
||||
|
||||
qseecom_fd = open("/dev/qseecom", O_RDWR);
|
||||
if (qseecom_fd < 0) {
|
||||
fprintf(stderr, "Failed to open /dev/qseecom device (%s)\n",
|
||||
strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
smcmod_fd = open("/dev/smcmod", O_RDWR);
|
||||
if (smcmod_fd < 0) {
|
||||
fprintf(stderr, "Failed to open /dev/smcmod device (%s)\n",
|
||||
strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
file = fopen(src_file, "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open %s (%s)\n", src_file, strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
fsize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
ret = ion_memalloc(&ionbuf, fsize, ION_QSECOM_HEAP_ID);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
read = fread(ionbuf.buffer, fsize, 1, file);
|
||||
if (read != 1) {
|
||||
fprintf(stderr, "Failed to read %s (%s)\n", src_file, strerror(errno));
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ion_buffer_clean_inval(&ionbuf, ION_IOC_CLEAN_INV_CACHES);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
ret = ioctl(qseecom_fd, QSEECOM_IOCTL_PERF_ENABLE_REQ);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
ret = is_encrypted(smcmod_fd, &ionbuf, fsize, &md_ctx, &offset);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (ret == 1) {
|
||||
fprintf(stdout, "decrypting %s ...\n", src_file);
|
||||
ret = decrypt(smcmod_fd, &ionbuf, fsize, md_ctx, offset);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
ion_buffer_clean_inval(&ionbuf, ION_IOC_INV_CACHES);
|
||||
|
||||
ret = save_file(dst_file, ionbuf.buffer + offset, fsize - offset);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
fprintf(stdout, "decrypting done!\n");
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ionbuf.ion_fd >= 0)
|
||||
ion_memfree(&ionbuf);
|
||||
|
||||
if (qseecom_fd >= 0) {
|
||||
ioctl(qseecom_fd, QSEECOM_IOCTL_PERF_DISABLE_REQ);
|
||||
close(qseecom_fd);
|
||||
}
|
||||
|
||||
if (smcmod_fd >= 0)
|
||||
close(smcmod_fd);
|
||||
|
||||
if (file)
|
||||
fclose(file);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DEC_H__
|
||||
#define __DEC_H__
|
||||
int decrypt_image(const char *src_file, const char *dst_file);
|
||||
#endif
|
|
@ -0,0 +1,593 @@
|
|||
/*
|
||||
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _LARGEFILE64_SOURCE /* enable lseek64() */
|
||||
|
||||
/******************************************************************************
|
||||
* INCLUDE SECTION
|
||||
******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "gpt-utils.h"
|
||||
#include "sparse_crc32.h"
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* DEFINE SECTION
|
||||
******************************************************************************/
|
||||
#define BLK_DEV_FILE "/dev/block/mmcblk0"
|
||||
|
||||
/* list the names of the backed-up partitions to be swapped */
|
||||
#define PTN_SWAP_LIST "sbl1", "rpm", "tz", "aboot"
|
||||
/* extension used for the backup partitions - tzbak, abootbak, etc. */
|
||||
#define BAK_PTN_NAME_EXT "bak"
|
||||
|
||||
#define LBA_SIZE 512
|
||||
|
||||
/* GPT defines */
|
||||
#define GPT_SIGNATURE "EFI PART"
|
||||
#define HEADER_SIZE_OFFSET 12
|
||||
#define HEADER_CRC_OFFSET 16
|
||||
#define PRIMARY_HEADER_OFFSET 24
|
||||
#define BACKUP_HEADER_OFFSET 32
|
||||
#define FIRST_USABLE_LBA_OFFSET 40
|
||||
#define LAST_USABLE_LBA_OFFSET 48
|
||||
#define PENTRIES_OFFSET 72
|
||||
#define PARTITION_COUNT_OFFSET 80
|
||||
#define PENTRY_SIZE_OFFSET 84
|
||||
#define PARTITION_CRC_OFFSET 88
|
||||
|
||||
#define TYPE_GUID_OFFSET 0
|
||||
#define TYPE_GUID_SIZE 16
|
||||
#define UNIQUE_GUID_OFFSET 16
|
||||
#define FIRST_LBA_OFFSET 32
|
||||
#define LAST_LBA_OFFSET 40
|
||||
#define ATTRIBUTE_FLAG_OFFSET 48
|
||||
#define PARTITION_NAME_OFFSET 56
|
||||
|
||||
#define MAX_GPT_NAME_SIZE 72
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* MACROS
|
||||
******************************************************************************/
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define GET_4_BYTES(ptr) ((uint32_t) *((uint8_t *)(ptr)) | \
|
||||
((uint32_t) *((uint8_t *)(ptr) + 1) << 8) | \
|
||||
((uint32_t) *((uint8_t *)(ptr) + 2) << 16) | \
|
||||
((uint32_t) *((uint8_t *)(ptr) + 3) << 24))
|
||||
|
||||
#define GET_8_BYTES(ptr) ((uint64_t) *((uint8_t *)(ptr)) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 1) << 8) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 2) << 16) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 3) << 24) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 4) << 32) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 5) << 40) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 6) << 48) | \
|
||||
((uint64_t) *((uint8_t *)(ptr) + 7) << 56))
|
||||
|
||||
#define PUT_4_BYTES(ptr, y) *((uint8_t *)(ptr)) = (y) & 0xff; \
|
||||
*((uint8_t *)(ptr) + 1) = ((y) >> 8) & 0xff; \
|
||||
*((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
|
||||
*((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* TYPES
|
||||
******************************************************************************/
|
||||
enum gpt_instance {
|
||||
PRIMARY_GPT = 0,
|
||||
SECONDARY_GPT
|
||||
};
|
||||
|
||||
enum boot_chain {
|
||||
NORMAL_BOOT = 0,
|
||||
BACKUP_BOOT
|
||||
};
|
||||
|
||||
enum gpt_state {
|
||||
GPT_OK = 0,
|
||||
GPT_BAD_SIGNATURE,
|
||||
GPT_BAD_CRC
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* FUNCTIONS
|
||||
******************************************************************************/
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Read/Write len bytes from/to block dev
|
||||
*
|
||||
* \param [in] fd block dev file descriptor (returned from open)
|
||||
* \param [in] rw RW flag: 0 - read, != 0 - write
|
||||
* \param [in] offset block dev offset [bytes] - RW start position
|
||||
* \param [in] buf Pointer to the buffer containing the data
|
||||
* \param [in] len RW size in bytes. Buf must be at least that big
|
||||
*
|
||||
* \return 0 on success
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
static int blk_rw(int fd, int rw, int64_t offset, uint8_t *buf, unsigned len)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (lseek64(fd, offset, SEEK_SET) < 0) {
|
||||
fprintf(stderr, "block dev lseek64 %lld failed: %s\n", offset,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rw)
|
||||
r = write(fd, buf, len);
|
||||
else
|
||||
r = read(fd, buf, len);
|
||||
|
||||
if (r < 0)
|
||||
fprintf(stderr, "block dev %s failed: %s\n", rw ? "write" : "read",
|
||||
strerror(errno));
|
||||
else
|
||||
r = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Search within GPT for partition entry with the given name
|
||||
* or it's backup twin (name-bak).
|
||||
*
|
||||
* \param [in] ptn_name Partition name to seek
|
||||
* \param [in] pentries_start Partition entries array start pointer
|
||||
* \param [in] pentries_end Partition entries array end pointer
|
||||
* \param [in] pentry_size Single partition entry size [bytes]
|
||||
*
|
||||
* \return First partition entry pointer that matches the name or NULL
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
static uint8_t *gpt_pentry_seek(const char *ptn_name,
|
||||
const uint8_t *pentries_start,
|
||||
const uint8_t *pentries_end,
|
||||
uint32_t pentry_size)
|
||||
{
|
||||
char *pentry_name;
|
||||
unsigned len = strlen(ptn_name);
|
||||
|
||||
for (pentry_name = (char *) (pentries_start + PARTITION_NAME_OFFSET);
|
||||
pentry_name < (char *) pentries_end; pentry_name += pentry_size) {
|
||||
char name8[MAX_GPT_NAME_SIZE / 2];
|
||||
unsigned i;
|
||||
|
||||
/* Partition names in GPT are UTF-16 - ignoring UTF-16 2nd byte */
|
||||
for (i = 0; i < sizeof(name8); i++)
|
||||
name8[i] = pentry_name[i * 2];
|
||||
if (!strncmp(ptn_name, name8, len))
|
||||
if (name8[len] == 0 || !strcmp(&name8[len], BAK_PTN_NAME_EXT))
|
||||
return (uint8_t *) (pentry_name - PARTITION_NAME_OFFSET);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Swaps boot chain in GPT partition entries array
|
||||
*
|
||||
* \param [in] pentries_start Partition entries array start
|
||||
* \param [in] pentries_end Partition entries array end
|
||||
* \param [in] pentry_size Single partition entry size
|
||||
*
|
||||
* \return 0 on success
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
static int gpt_boot_chain_swap(const uint8_t *pentries_start,
|
||||
const uint8_t *pentries_end,
|
||||
uint32_t pentry_size)
|
||||
{
|
||||
const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ptn_swap_list); i++) {
|
||||
uint8_t *ptn_entry;
|
||||
uint8_t *ptn_bak_entry;
|
||||
uint8_t ptn_swap[TYPE_GUID_SIZE];
|
||||
|
||||
ptn_entry = gpt_pentry_seek(ptn_swap_list[i], pentries_start,
|
||||
pentries_end, pentry_size);
|
||||
if (ptn_entry == NULL)
|
||||
break;
|
||||
ptn_bak_entry = gpt_pentry_seek(ptn_swap_list[i],
|
||||
ptn_entry + pentry_size, pentries_end, pentry_size);
|
||||
if (ptn_bak_entry == NULL)
|
||||
break;
|
||||
|
||||
/* swap primary <-> backup partition entries */
|
||||
memcpy(ptn_swap, ptn_entry + TYPE_GUID_OFFSET, TYPE_GUID_SIZE);
|
||||
memcpy(ptn_entry + TYPE_GUID_OFFSET,
|
||||
ptn_bak_entry + TYPE_GUID_OFFSET, TYPE_GUID_SIZE);
|
||||
memcpy(ptn_bak_entry + TYPE_GUID_OFFSET, ptn_swap, TYPE_GUID_SIZE);
|
||||
}
|
||||
|
||||
if (i != ARRAY_SIZE(ptn_swap_list)) {
|
||||
fprintf(stderr,
|
||||
"Partition '%s' not found in GPT partition entries array\n",
|
||||
ptn_swap_list[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Sets secondary GPT boot chain
|
||||
*
|
||||
* \param [in] fd block dev file descriptor
|
||||
* \param [in] boot Boot chain to switch to
|
||||
*
|
||||
* \return 0 on success
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
static int gpt2_set_boot_chain(int fd, enum boot_chain boot)
|
||||
{
|
||||
int64_t gpt2_header_offset;
|
||||
uint64_t pentries_start_offset;
|
||||
uint32_t gpt_header_size;
|
||||
uint32_t pentry_size;
|
||||
uint32_t pentries_array_size;
|
||||
|
||||
uint8_t gpt_header[LBA_SIZE];
|
||||
uint8_t *pentries;
|
||||
uint32_t crc;
|
||||
|
||||
int r;
|
||||
|
||||
gpt2_header_offset = lseek64(fd, 0, SEEK_END) - LBA_SIZE;
|
||||
if (gpt2_header_offset < 0) {
|
||||
fprintf(stderr, "Getting secondary GPT header offset failed: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read primary GPT header from block dev */
|
||||
r = blk_rw(fd, 0, LBA_SIZE, gpt_header, LBA_SIZE);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
pentries_start_offset =
|
||||
GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * LBA_SIZE;
|
||||
pentry_size = GET_4_BYTES(gpt_header + PENTRY_SIZE_OFFSET);
|
||||
pentries_array_size =
|
||||
GET_4_BYTES(gpt_header + PARTITION_COUNT_OFFSET) * pentry_size;
|
||||
|
||||
pentries = (uint8_t *) calloc(1, pentries_array_size);
|
||||
if (pentries == NULL) {
|
||||
fprintf(stderr,
|
||||
"Failed to allocate memory for GPT partition entries array\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read primary GPT partititon entries array from block dev */
|
||||
r = blk_rw(fd, 0, pentries_start_offset, pentries, pentries_array_size);
|
||||
if (r)
|
||||
goto EXIT;
|
||||
|
||||
crc = sparse_crc32(0, pentries, pentries_array_size);
|
||||
if (GET_4_BYTES(gpt_header + PARTITION_CRC_OFFSET) != crc) {
|
||||
fprintf(stderr, "Primary GPT partition entries array CRC invalid\n");
|
||||
r = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
/* Read secondary GPT header from block dev */
|
||||
r = blk_rw(fd, 0, gpt2_header_offset, gpt_header, LBA_SIZE);
|
||||
if (r)
|
||||
goto EXIT;
|
||||
|
||||
gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
|
||||
pentries_start_offset =
|
||||
GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * LBA_SIZE;
|
||||
|
||||
if (boot == BACKUP_BOOT) {
|
||||
r = gpt_boot_chain_swap(pentries, pentries + pentries_array_size,
|
||||
pentry_size);
|
||||
if (r)
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
crc = sparse_crc32(0, pentries, pentries_array_size);
|
||||
PUT_4_BYTES(gpt_header + PARTITION_CRC_OFFSET, crc);
|
||||
|
||||
/* header CRC is calculated with this field cleared */
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
|
||||
crc = sparse_crc32(0, gpt_header, gpt_header_size);
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
|
||||
|
||||
/* Write the modified GPT header back to block dev */
|
||||
r = blk_rw(fd, 1, gpt2_header_offset, gpt_header, LBA_SIZE);
|
||||
if (!r)
|
||||
/* Write the modified GPT partititon entries array back to block dev */
|
||||
r = blk_rw(fd, 1, pentries_start_offset, pentries,
|
||||
pentries_array_size);
|
||||
|
||||
EXIT:
|
||||
free(pentries);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Checks GPT state (header signature and CRC)
|
||||
*
|
||||
* \param [in] fd block dev file descriptor
|
||||
* \param [in] gpt GPT header to be checked
|
||||
* \param [out] state GPT header state
|
||||
*
|
||||
* \return 0 on success
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
static int gpt_get_state(int fd, enum gpt_instance gpt, enum gpt_state *state)
|
||||
{
|
||||
int64_t gpt_header_offset;
|
||||
uint32_t gpt_header_size;
|
||||
uint8_t gpt_header[LBA_SIZE];
|
||||
uint32_t crc;
|
||||
|
||||
*state = GPT_OK;
|
||||
|
||||
if (gpt == PRIMARY_GPT)
|
||||
gpt_header_offset = LBA_SIZE;
|
||||
else {
|
||||
gpt_header_offset = lseek64(fd, 0, SEEK_END) - LBA_SIZE;
|
||||
if (gpt_header_offset < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (blk_rw(fd, 0, gpt_header_offset, gpt_header, LBA_SIZE))
|
||||
return -1;
|
||||
|
||||
if (memcmp(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE)))
|
||||
*state = GPT_BAD_SIGNATURE;
|
||||
|
||||
gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
|
||||
|
||||
crc = GET_4_BYTES(gpt_header + HEADER_CRC_OFFSET);
|
||||
/* header CRC is calculated with this field cleared */
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
|
||||
if (sparse_crc32(0, gpt_header, gpt_header_size) != crc)
|
||||
*state = GPT_BAD_CRC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Sets GPT header state (used to corrupt and fix GPT signature)
|
||||
*
|
||||
* \param [in] fd block dev file descriptor
|
||||
* \param [in] gpt GPT header to be checked
|
||||
* \param [in] state GPT header state to set (GPT_OK or GPT_BAD_SIGNATURE)
|
||||
*
|
||||
* \return 0 on success
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
static int gpt_set_state(int fd, enum gpt_instance gpt, enum gpt_state state)
|
||||
{
|
||||
int64_t gpt_header_offset;
|
||||
uint32_t gpt_header_size;
|
||||
uint8_t gpt_header[LBA_SIZE];
|
||||
uint32_t crc;
|
||||
|
||||
if (gpt == PRIMARY_GPT)
|
||||
gpt_header_offset = LBA_SIZE;
|
||||
else {
|
||||
gpt_header_offset = lseek64(fd, 0, SEEK_END) - LBA_SIZE;
|
||||
if (gpt_header_offset < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (blk_rw(fd, 0, gpt_header_offset, gpt_header, LBA_SIZE))
|
||||
return -1;
|
||||
|
||||
if (state == GPT_OK)
|
||||
memcpy(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE));
|
||||
else if (state == GPT_BAD_SIGNATURE)
|
||||
*gpt_header = 0;
|
||||
else
|
||||
return -1;
|
||||
|
||||
gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
|
||||
|
||||
/* header CRC is calculated with this field cleared */
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
|
||||
crc = sparse_crc32(0, gpt_header, gpt_header_size);
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
|
||||
|
||||
if (blk_rw(fd, 1, gpt_header_offset, gpt_header, LBA_SIZE))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ==========================================================================
|
||||
*
|
||||
* \brief Prepare for certain boot partitions update stage
|
||||
*
|
||||
* \param [in] stage Update stage reached
|
||||
*
|
||||
* \return 0 on success, < 0 on error
|
||||
*
|
||||
* ==========================================================================
|
||||
*/
|
||||
int prepare_boot_update(enum boot_update_stage stage)
|
||||
{
|
||||
int r, fd;
|
||||
enum gpt_state gpt_prim, gpt_second;
|
||||
enum boot_update_stage internal_stage;
|
||||
|
||||
fd = open(BLK_DEV_FILE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Opening '%s' failed: %s\n", BLK_DEV_FILE,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = gpt_get_state(fd, PRIMARY_GPT, &gpt_prim) ||
|
||||
gpt_get_state(fd, SECONDARY_GPT, &gpt_second);
|
||||
if (r) {
|
||||
fprintf(stderr, "Getting GPT headers state failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
/* These 2 combinations are unexpected and unacceptable */
|
||||
if (gpt_prim == GPT_BAD_CRC || gpt_second == GPT_BAD_CRC) {
|
||||
fprintf(stderr, "GPT headers CRC corruption detected, aborting\n");
|
||||
r = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
if (gpt_prim == GPT_BAD_SIGNATURE && gpt_second == GPT_BAD_SIGNATURE) {
|
||||
fprintf(stderr, "Both GPT headers corrupted, aborting\n");
|
||||
r = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
/* Check internal update stage according GPT headers' state */
|
||||
if (gpt_prim == GPT_OK && gpt_second == GPT_OK)
|
||||
internal_stage = UPDATE_MAIN;
|
||||
else if (gpt_prim == GPT_BAD_SIGNATURE)
|
||||
internal_stage = UPDATE_BACKUP;
|
||||
else if (gpt_second == GPT_BAD_SIGNATURE)
|
||||
internal_stage = UPDATE_FINALIZE;
|
||||
else {
|
||||
fprintf(stderr, "Abnormal GPTs state: primary (%d), secondary (%d), "
|
||||
"aborting\n", gpt_prim, gpt_second);
|
||||
r = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
/* Stage already set - ready for update, exitting */
|
||||
if ((int) stage == (int) internal_stage - 1)
|
||||
goto EXIT;
|
||||
/* Unexpected stage given */
|
||||
if (stage != internal_stage) {
|
||||
r = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case UPDATE_MAIN:
|
||||
fprintf(stdout, "Preparing main boot partitions update\n");
|
||||
|
||||
r = gpt2_set_boot_chain(fd, BACKUP_BOOT);
|
||||
if (r) {
|
||||
fprintf(stderr, "Setting secondary GPT to backup boot failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
r = gpt_set_state(fd, PRIMARY_GPT, GPT_BAD_SIGNATURE);
|
||||
if (r) {
|
||||
fprintf(stderr, "Corrupting primary GPT header failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
break;
|
||||
case UPDATE_BACKUP:
|
||||
fprintf(stdout, "Preparing backup boot partitions update\n");
|
||||
|
||||
r = gpt_set_state(fd, PRIMARY_GPT, GPT_OK);
|
||||
if (r) {
|
||||
fprintf(stderr, "Fixing primary GPT header failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
r = gpt_set_state(fd, SECONDARY_GPT, GPT_BAD_SIGNATURE);
|
||||
if (r) {
|
||||
fprintf(stderr, "Corrupting secondary GPT header failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
break;
|
||||
case UPDATE_FINALIZE:
|
||||
fprintf(stdout, "Finalizing boot partitions update\n");
|
||||
|
||||
r = gpt2_set_boot_chain(fd, NORMAL_BOOT);
|
||||
if (r) {
|
||||
fprintf(stderr, "Setting secondary GPT to normal boot failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
r = gpt_set_state(fd, SECONDARY_GPT, GPT_OK);
|
||||
if (r) {
|
||||
fprintf(stderr, "Fixing secondary GPT header failed\n");
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
||||
EXIT:
|
||||
fsync(fd);
|
||||
close(fd);
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __GPT_UTILS_H__
|
||||
#define __GPT_UTILS_H__
|
||||
|
||||
/******************************************************************************
|
||||
* TYPES
|
||||
******************************************************************************/
|
||||
enum boot_update_stage {
|
||||
UPDATE_MAIN = 1,
|
||||
UPDATE_BACKUP,
|
||||
UPDATE_FINALIZE
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* FUNCTION PROTOTYPES
|
||||
******************************************************************************/
|
||||
int prepare_boot_update(enum boot_update_stage stage);
|
||||
|
||||
#endif /* __GPT_UTILS_H__ */
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "edify/expr.h"
|
||||
#include "dec.h"
|
||||
#include "gpt-utils.h"
|
||||
|
||||
Value* DecryptFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
int rc = -1;
|
||||
const char *src_file, *dst_file;
|
||||
|
||||
if (argc != 2)
|
||||
return ErrorAbort(state, "%s expects 2 args, got %d", name, argc);
|
||||
|
||||
if (ReadArgs(state, argv, 2, &src_file, &dst_file))
|
||||
return NULL;
|
||||
|
||||
rc = decrypt_image(src_file, dst_file);
|
||||
|
||||
return StringValue(strdup(rc >= 0 ? "t" : ""));
|
||||
}
|
||||
|
||||
Value* BootUpdateFn(const char* name, State* state, int argc, Expr* argv[])
|
||||
{
|
||||
int rc = 0;
|
||||
char *stageStr;
|
||||
enum boot_update_stage stage;
|
||||
|
||||
if (argc != 1)
|
||||
return ErrorAbort(state, "%s() expects 1 args, got %d", name, argc);
|
||||
|
||||
if (ReadArgs(state, argv, 1, &stageStr))
|
||||
return NULL;
|
||||
|
||||
if (!strcmp(stageStr, "main"))
|
||||
stage = UPDATE_MAIN;
|
||||
else if (!strcmp(stageStr, "backup"))
|
||||
stage = UPDATE_BACKUP;
|
||||
else if (!strcmp(stageStr, "finalize"))
|
||||
stage = UPDATE_FINALIZE;
|
||||
else {
|
||||
fprintf(stderr, "Unrecognized boot update stage, exitting\n");
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = prepare_boot_update(stage);
|
||||
|
||||
return StringValue(strdup(rc ? "" : "t"));
|
||||
}
|
||||
|
||||
void Register_librecovery_updater_msm() {
|
||||
RegisterFunction("msm.decrypt", DecryptFn);
|
||||
RegisterFunction("msm.boot_update", BootUpdateFn);
|
||||
}
|
Loading…
Reference in New Issue