Merge commit 'f8dd04e1a5f94e7accf65a5375114ac7fa73f828' into HEAD
This commit is contained in:
+36
-8
@@ -309,7 +309,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
|
|||||||
// Save the contents of the given FileContents object under the given
|
// Save the contents of the given FileContents object under the given
|
||||||
// filename. Return 0 on success.
|
// filename. Return 0 on success.
|
||||||
int SaveFileContents(const char* filename, const FileContents* file) {
|
int SaveFileContents(const char* filename, const FileContents* file) {
|
||||||
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
printf("failed to open \"%s\" for write: %s\n",
|
printf("failed to open \"%s\" for write: %s\n",
|
||||||
filename, strerror(errno));
|
filename, strerror(errno));
|
||||||
@@ -324,8 +324,14 @@ int SaveFileContents(const char* filename, const FileContents* file) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fsync(fd);
|
if (fsync(fd) != 0) {
|
||||||
close(fd);
|
printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
printf("close of \"%s\" failed: %s\n", filename, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (chmod(filename, file->st.st_mode) != 0) {
|
if (chmod(filename, file->st.st_mode) != 0) {
|
||||||
printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
|
printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
|
||||||
@@ -408,7 +414,7 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
{
|
{
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
int success = 0;
|
int success = 0;
|
||||||
int fd = open(partition, O_RDWR);
|
int fd = open(partition, O_RDWR | O_SYNC);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
printf("failed to open %s: %s\n", partition, strerror(errno));
|
printf("failed to open %s: %s\n", partition, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -433,7 +439,22 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
}
|
}
|
||||||
start += written;
|
start += written;
|
||||||
}
|
}
|
||||||
fsync(fd);
|
if (fsync(fd) != 0) {
|
||||||
|
printf("failed to sync to %s (%s)\n",
|
||||||
|
partition, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
printf("failed to close %s (%s)\n",
|
||||||
|
partition, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fd = open(partition, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
printf("failed to reopen %s for verify (%s)\n",
|
||||||
|
partition, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// drop caches so our subsequent verification read
|
// drop caches so our subsequent verification read
|
||||||
// won't just be reading the cache.
|
// won't just be reading the cache.
|
||||||
@@ -919,7 +940,8 @@ static int GenerateTarget(FileContents* source_file,
|
|||||||
strcpy(outname, target_filename);
|
strcpy(outname, target_filename);
|
||||||
strcat(outname, ".patch");
|
strcat(outname, ".patch");
|
||||||
|
|
||||||
output = open(outname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
output = open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
|
||||||
|
S_IRUSR | S_IWUSR);
|
||||||
if (output < 0) {
|
if (output < 0) {
|
||||||
printf("failed to open output file %s: %s\n",
|
printf("failed to open output file %s: %s\n",
|
||||||
outname, strerror(errno));
|
outname, strerror(errno));
|
||||||
@@ -950,8 +972,14 @@ static int GenerateTarget(FileContents* source_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (output >= 0) {
|
if (output >= 0) {
|
||||||
fsync(output);
|
if (fsync(output) != 0) {
|
||||||
close(output);
|
printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno));
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
if (close(output) != 0) {
|
||||||
|
printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno));
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ static const char* ITEMS[] = {"reboot system now",
|
|||||||
"wipe cache partition",
|
"wipe cache partition",
|
||||||
"reboot to bootloader",
|
"reboot to bootloader",
|
||||||
"power down",
|
"power down",
|
||||||
|
"view recovery logs",
|
||||||
NULL };
|
NULL };
|
||||||
|
|
||||||
class DefaultDevice : public Device {
|
class DefaultDevice : public Device {
|
||||||
@@ -69,6 +70,7 @@ class DefaultDevice : public Device {
|
|||||||
case 3: return WIPE_CACHE;
|
case 3: return WIPE_CACHE;
|
||||||
case 4: return REBOOT_BOOTLOADER;
|
case 4: return REBOOT_BOOTLOADER;
|
||||||
case 5: return SHUTDOWN;
|
case 5: return SHUTDOWN;
|
||||||
|
case 6: return READ_RECOVERY_LASTLOG;
|
||||||
default: return NO_ACTION;
|
default: return NO_ACTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class Device {
|
|||||||
enum BuiltinAction { NO_ACTION, REBOOT, APPLY_EXT,
|
enum BuiltinAction { NO_ACTION, REBOOT, APPLY_EXT,
|
||||||
APPLY_CACHE, // APPLY_CACHE is deprecated; has no effect
|
APPLY_CACHE, // APPLY_CACHE is deprecated; has no effect
|
||||||
APPLY_ADB_SIDELOAD, WIPE_DATA, WIPE_CACHE,
|
APPLY_ADB_SIDELOAD, WIPE_DATA, WIPE_CACHE,
|
||||||
REBOOT_BOOTLOADER, SHUTDOWN };
|
REBOOT_BOOTLOADER, SHUTDOWN, READ_RECOVERY_LASTLOG };
|
||||||
|
|
||||||
// Perform a recovery action selected from the menu.
|
// Perform a recovery action selected from the menu.
|
||||||
// 'menu_position' will be the item number of the selected menu
|
// 'menu_position' will be the item number of the selected menu
|
||||||
|
|||||||
+7
-1
@@ -30,6 +30,7 @@ on init
|
|||||||
chmod 0775 /tmp
|
chmod 0775 /tmp
|
||||||
|
|
||||||
write /proc/sys/kernel/panic_on_oops 1
|
write /proc/sys/kernel/panic_on_oops 1
|
||||||
|
write /proc/sys/vm/max_map_count 1000000
|
||||||
|
|
||||||
on fs
|
on fs
|
||||||
mkdir /dev/usb-ffs 0770 shell shell
|
mkdir /dev/usb-ffs 0770 shell shell
|
||||||
@@ -45,7 +46,6 @@ on fs
|
|||||||
write /sys/class/android_usb/android0/iProduct ${ro.product.model}
|
write /sys/class/android_usb/android0/iProduct ${ro.product.model}
|
||||||
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
|
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
|
||||||
|
|
||||||
|
|
||||||
on boot
|
on boot
|
||||||
ifup lo
|
ifup lo
|
||||||
hostname localhost
|
hostname localhost
|
||||||
@@ -57,6 +57,9 @@ on boot
|
|||||||
on load_all_props_action
|
on load_all_props_action
|
||||||
load_all_props
|
load_all_props
|
||||||
|
|
||||||
|
on firmware_mounts_complete
|
||||||
|
rm /dev/.booting
|
||||||
|
|
||||||
# Mount filesystems and start core system services.
|
# Mount filesystems and start core system services.
|
||||||
on late-init
|
on late-init
|
||||||
trigger early-fs
|
trigger early-fs
|
||||||
@@ -69,6 +72,9 @@ on late-init
|
|||||||
# issued fs triggers have completed.
|
# issued fs triggers have completed.
|
||||||
trigger load_all_props_action
|
trigger load_all_props_action
|
||||||
|
|
||||||
|
# Remove a file to wake up anything waiting for firmware
|
||||||
|
trigger firmware_mounts_complete
|
||||||
|
|
||||||
trigger early-boot
|
trigger early-boot
|
||||||
trigger boot
|
trigger boot
|
||||||
|
|
||||||
|
|||||||
@@ -180,6 +180,18 @@ static gr_surface fbdev_init(minui_backend* backend) {
|
|||||||
|
|
||||||
static gr_surface fbdev_flip(minui_backend* backend __unused) {
|
static gr_surface fbdev_flip(minui_backend* backend __unused) {
|
||||||
if (double_buffered) {
|
if (double_buffered) {
|
||||||
|
#if defined(RECOVERY_BGRA)
|
||||||
|
// In case of BGRA, do some byte swapping
|
||||||
|
unsigned int idx;
|
||||||
|
unsigned char tmp;
|
||||||
|
unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data;
|
||||||
|
for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes);
|
||||||
|
idx += 4) {
|
||||||
|
tmp = ucfb_vaddr[idx];
|
||||||
|
ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2];
|
||||||
|
ucfb_vaddr[idx + 2] = tmp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Change gr_draw to point to the buffer currently displayed,
|
// Change gr_draw to point to the buffer currently displayed,
|
||||||
// then flip the driver so we're displaying the other buffer
|
// then flip the driver so we're displaying the other buffer
|
||||||
// instead.
|
// instead.
|
||||||
|
|||||||
+8
-2
@@ -1063,7 +1063,8 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
|||||||
setfscreatecon(secontext);
|
setfscreatecon(secontext);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = creat(targetFile, UNZIP_FILEMODE);
|
int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC
|
||||||
|
, UNZIP_FILEMODE);
|
||||||
|
|
||||||
if (secontext) {
|
if (secontext) {
|
||||||
freecon(secontext);
|
freecon(secontext);
|
||||||
@@ -1078,7 +1079,12 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
|
bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
|
||||||
close(fd);
|
if (ok) {
|
||||||
|
ok = (fsync(fd) == 0);
|
||||||
|
}
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Error extracting \"%s\"\n", targetFile);
|
LOGE("Error extracting \"%s\"\n", targetFile);
|
||||||
ok = false;
|
ok = false;
|
||||||
|
|||||||
+161
-4
@@ -25,6 +25,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/klog.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -76,6 +77,13 @@ static const char *CACHE_ROOT = "/cache";
|
|||||||
static const char *SDCARD_ROOT = "/sdcard";
|
static const char *SDCARD_ROOT = "/sdcard";
|
||||||
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
||||||
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
|
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
|
||||||
|
static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
||||||
|
#define KLOG_DEFAULT_LEN (64 * 1024)
|
||||||
|
|
||||||
|
#define KEEP_LOG_COUNT 10
|
||||||
|
|
||||||
|
// Number of lines per page when displaying a file on screen
|
||||||
|
#define LINES_PER_PAGE 30
|
||||||
|
|
||||||
RecoveryUI* ui = NULL;
|
RecoveryUI* ui = NULL;
|
||||||
char* locale = NULL;
|
char* locale = NULL;
|
||||||
@@ -166,6 +174,12 @@ bool is_ro_debuggable() {
|
|||||||
return (property_get("ro.debuggable", value, NULL) == 1 && value[0] == '1');
|
return (property_get("ro.debuggable", value, NULL) == 1 && value[0] == '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void redirect_stdio(const char* filename) {
|
||||||
|
// If these fail, there's not really anywhere to complain...
|
||||||
|
freopen(filename, "a", stdout); setbuf(stdout, NULL);
|
||||||
|
freopen(filename, "a", stderr); setbuf(stderr, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// close a file, log an error if the error indicator is set
|
// close a file, log an error if the error indicator is set
|
||||||
static void
|
static void
|
||||||
check_and_fclose(FILE *fp, const char *name) {
|
check_and_fclose(FILE *fp, const char *name) {
|
||||||
@@ -256,6 +270,44 @@ set_sdcard_update_bootloader_message() {
|
|||||||
set_bootloader_message(&boot);
|
set_bootloader_message(&boot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read from kernel log into buffer and write out to file
|
||||||
|
static void
|
||||||
|
save_kernel_log(const char *destination) {
|
||||||
|
int n;
|
||||||
|
char *buffer;
|
||||||
|
int klog_buf_len;
|
||||||
|
FILE *log;
|
||||||
|
|
||||||
|
klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
|
||||||
|
if (klog_buf_len <= 0) {
|
||||||
|
LOGE("Error getting klog size (%s), using default\n", strerror(errno));
|
||||||
|
klog_buf_len = KLOG_DEFAULT_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = (char *)malloc(klog_buf_len);
|
||||||
|
if (!buffer) {
|
||||||
|
LOGE("Can't alloc %d bytes for klog buffer\n", klog_buf_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = klogctl(KLOG_READ_ALL, buffer, klog_buf_len);
|
||||||
|
if (n < 0) {
|
||||||
|
LOGE("Error in reading klog (%s)\n", strerror(errno));
|
||||||
|
free(buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log = fopen_path(destination, "w");
|
||||||
|
if (log == NULL) {
|
||||||
|
LOGE("Can't open %s\n", destination);
|
||||||
|
free(buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fwrite(buffer, n, 1, log);
|
||||||
|
check_and_fclose(log, destination);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
// How much of the temp log we have copied to the copy in cache.
|
// How much of the temp log we have copied to the copy in cache.
|
||||||
static long tmplog_offset = 0;
|
static long tmplog_offset = 0;
|
||||||
|
|
||||||
@@ -303,8 +355,11 @@ copy_logs() {
|
|||||||
copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
|
copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
|
||||||
copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
|
copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
|
||||||
copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
|
copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
|
||||||
|
save_kernel_log(LAST_KMSG_FILE);
|
||||||
chmod(LOG_FILE, 0600);
|
chmod(LOG_FILE, 0600);
|
||||||
chown(LOG_FILE, 1000, 1000); // system user
|
chown(LOG_FILE, 1000, 1000); // system user
|
||||||
|
chmod(LAST_KMSG_FILE, 0600);
|
||||||
|
chown(LAST_KMSG_FILE, 1000, 1000); // system user
|
||||||
chmod(LAST_LOG_FILE, 0640);
|
chmod(LAST_LOG_FILE, 0640);
|
||||||
chmod(LAST_INSTALL_FILE, 0644);
|
chmod(LAST_INSTALL_FILE, 0644);
|
||||||
sync();
|
sync();
|
||||||
@@ -670,6 +725,106 @@ wipe_data(int confirm, Device* device) {
|
|||||||
ui->Print("Data wipe complete.\n");
|
ui->Print("Data wipe complete.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void file_to_ui(const char* fn) {
|
||||||
|
FILE *fp = fopen_path(fn, "re");
|
||||||
|
if (fp == NULL) {
|
||||||
|
ui->Print(" Unable to open %s: %s\n", fn, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char line[1024];
|
||||||
|
int ct = 0;
|
||||||
|
int key = 0;
|
||||||
|
redirect_stdio("/dev/null");
|
||||||
|
while(fgets(line, sizeof(line), fp) != NULL) {
|
||||||
|
ui->Print("%s", line);
|
||||||
|
ct++;
|
||||||
|
if (ct % LINES_PER_PAGE == 0) {
|
||||||
|
// give the user time to glance at the entries
|
||||||
|
key = ui->WaitKey();
|
||||||
|
|
||||||
|
if (key == KEY_POWER) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == KEY_VOLUMEUP) {
|
||||||
|
// Go back by seeking to the beginning and dumping ct - n
|
||||||
|
// lines. It's ugly, but this way we don't need to store
|
||||||
|
// the previous offsets. The files we're dumping here aren't
|
||||||
|
// expected to be very large.
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ct -= 2 * LINES_PER_PAGE;
|
||||||
|
if (ct < 0) {
|
||||||
|
ct = 0;
|
||||||
|
}
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
for (i = 0; i < ct; i++) {
|
||||||
|
fgets(line, sizeof(line), fp);
|
||||||
|
}
|
||||||
|
ui->Print("^^^^^^^^^^\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user didn't abort, then give the user time to glance at
|
||||||
|
// the end of the log, sorry, no rewind here
|
||||||
|
if (key != KEY_POWER) {
|
||||||
|
ui->Print("\n--END-- (press any key)\n");
|
||||||
|
ui->WaitKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect_stdio(TEMPORARY_LOG_FILE);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void choose_recovery_file(Device* device) {
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int n;
|
||||||
|
static const char** title_headers = NULL;
|
||||||
|
char *filename;
|
||||||
|
const char* headers[] = { "Select file to view",
|
||||||
|
"",
|
||||||
|
NULL };
|
||||||
|
// "Go back" + LAST_KMSG_FILE + KEEP_LOG_COUNT + terminating NULL entry
|
||||||
|
char* entries[KEEP_LOG_COUNT + 3];
|
||||||
|
memset(entries, 0, sizeof(entries));
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
entries[n++] = strdup("Go back");
|
||||||
|
|
||||||
|
// Add kernel kmsg file if available
|
||||||
|
if ((ensure_path_mounted(LAST_KMSG_FILE) == 0) && (access(LAST_KMSG_FILE, R_OK) == 0)) {
|
||||||
|
entries[n++] = strdup(LAST_KMSG_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add LAST_LOG_FILE + LAST_LOG_FILE.x
|
||||||
|
for (i = 0; i < KEEP_LOG_COUNT; i++) {
|
||||||
|
char *filename;
|
||||||
|
if (asprintf(&filename, (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i) == -1) {
|
||||||
|
// memory allocation failure - return early. Should never happen.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((ensure_path_mounted(filename) != 0) || (access(filename, R_OK) == -1)) {
|
||||||
|
free(filename);
|
||||||
|
entries[n++] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entries[n++] = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
title_headers = prepend_title((const char**)headers);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int chosen_item = get_menu_selection(title_headers, entries, 1, 0, device);
|
||||||
|
if (chosen_item == 0) break;
|
||||||
|
file_to_ui(entries[chosen_item]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(entries) / sizeof(*entries)); i++) {
|
||||||
|
free(entries[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION
|
// Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION
|
||||||
// means to take the default, which is to reboot or shutdown depending
|
// means to take the default, which is to reboot or shutdown depending
|
||||||
// on if the --shutdown_after flag was passed to recovery.
|
// on if the --shutdown_after flag was passed to recovery.
|
||||||
@@ -765,6 +920,10 @@ prompt_and_wait(Device* device, int status) {
|
|||||||
ui->Print("\nAPPLY_CACHE is deprecated.\n");
|
ui->Print("\nAPPLY_CACHE is deprecated.\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Device::READ_RECOVERY_LASTLOG:
|
||||||
|
choose_recovery_file(device);
|
||||||
|
break;
|
||||||
|
|
||||||
case Device::APPLY_ADB_SIDELOAD:
|
case Device::APPLY_ADB_SIDELOAD:
|
||||||
status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
|
status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
|
||||||
if (status >= 0) {
|
if (status >= 0) {
|
||||||
@@ -829,9 +988,7 @@ int
|
|||||||
main(int argc, char **argv) {
|
main(int argc, char **argv) {
|
||||||
time_t start = time(NULL);
|
time_t start = time(NULL);
|
||||||
|
|
||||||
// If these fail, there's not really anywhere to complain...
|
redirect_stdio(TEMPORARY_LOG_FILE);
|
||||||
freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
|
|
||||||
freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
|
|
||||||
|
|
||||||
// If this binary is started with the single argument "--adbd",
|
// If this binary is started with the single argument "--adbd",
|
||||||
// instead of being the normal recovery binary, it turns into kind
|
// instead of being the normal recovery binary, it turns into kind
|
||||||
@@ -849,7 +1006,7 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
load_volume_table();
|
load_volume_table();
|
||||||
ensure_path_mounted(LAST_LOG_FILE);
|
ensure_path_mounted(LAST_LOG_FILE);
|
||||||
rotate_last_logs(10);
|
rotate_last_logs(KEEP_LOG_COUNT);
|
||||||
get_args(&argc, &argv);
|
get_args(&argc, &argv);
|
||||||
|
|
||||||
const char *send_intent = NULL;
|
const char *send_intent = NULL;
|
||||||
|
|||||||
+18
-5
@@ -166,7 +166,12 @@ char* parse_recovery_command_file()
|
|||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
FILE* fo = fopen(RECOVERY_COMMAND_FILE_TMP, "w");
|
int fd = open(RECOVERY_COMMAND_FILE_TMP, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
|
||||||
|
if (fd < 0) {
|
||||||
|
ALOGE("failed to open %s\n", RECOVERY_COMMAND_FILE_TMP);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
FILE* fo = fdopen(fd, "w");
|
||||||
|
|
||||||
while (fgets(temp, sizeof(temp), f)) {
|
while (fgets(temp, sizeof(temp), f)) {
|
||||||
printf("read: %s", temp);
|
printf("read: %s", temp);
|
||||||
@@ -177,6 +182,7 @@ char* parse_recovery_command_file()
|
|||||||
fputs(temp, fo);
|
fputs(temp, fo);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
fsync(fd);
|
||||||
fclose(fo);
|
fclose(fo);
|
||||||
|
|
||||||
if (fn) {
|
if (fn) {
|
||||||
@@ -192,7 +198,12 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de
|
|||||||
struct stat sb;
|
struct stat sb;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
FILE* mapf = fopen(map_file, "w");
|
int mapfd = open(map_file, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
|
||||||
|
if (mapfd < 0) {
|
||||||
|
ALOGE("failed to open %s\n", map_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
FILE* mapf = fdopen(mapfd, "w");
|
||||||
|
|
||||||
ret = stat(path, &sb);
|
ret = stat(path, &sb);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@@ -234,7 +245,7 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de
|
|||||||
|
|
||||||
int wfd = -1;
|
int wfd = -1;
|
||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
wfd = open(blk_dev, O_WRONLY);
|
wfd = open(blk_dev, O_WRONLY | O_SYNC);
|
||||||
if (wfd < 0) {
|
if (wfd < 0) {
|
||||||
ALOGE("failed to open fd for writing: %s\n", strerror(errno));
|
ALOGE("failed to open fd for writing: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -304,9 +315,11 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de
|
|||||||
fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]);
|
fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fsync(mapfd);
|
||||||
fclose(mapf);
|
fclose(mapf);
|
||||||
close(fd);
|
close(fd);
|
||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
|
fsync(wfd);
|
||||||
close(wfd);
|
close(wfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +333,7 @@ void wipe_misc() {
|
|||||||
struct fstab_rec* v = &fstab->recs[i];
|
struct fstab_rec* v = &fstab->recs[i];
|
||||||
if (!v->mount_point) continue;
|
if (!v->mount_point) continue;
|
||||||
if (strcmp(v->mount_point, "/misc") == 0) {
|
if (strcmp(v->mount_point, "/misc") == 0) {
|
||||||
int fd = open(v->blk_device, O_WRONLY);
|
int fd = open(v->blk_device, O_WRONLY | O_SYNC);
|
||||||
uint8_t zeroes[1088]; // sizeof(bootloader_message) from recovery
|
uint8_t zeroes[1088]; // sizeof(bootloader_message) from recovery
|
||||||
memset(zeroes, 0, sizeof(zeroes));
|
memset(zeroes, 0, sizeof(zeroes));
|
||||||
|
|
||||||
@@ -335,7 +348,7 @@ void wipe_misc() {
|
|||||||
written += w;
|
written += w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fsync(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,16 @@ LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
|
|||||||
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
|
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
|
||||||
LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc
|
LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc
|
||||||
LOCAL_STATIC_LIBRARIES += libselinux
|
LOCAL_STATIC_LIBRARIES += libselinux
|
||||||
|
tune2fs_static_libraries := \
|
||||||
|
libext2_com_err \
|
||||||
|
libext2_blkid \
|
||||||
|
libext2_quota \
|
||||||
|
libext2_uuid_static \
|
||||||
|
libext2_e2p \
|
||||||
|
libext2fs
|
||||||
|
LOCAL_STATIC_LIBRARIES += libtune2fs $(tune2fs_static_libraries)
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES += external/e2fsprogs/misc
|
||||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
|
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
|
||||||
|
|
||||||
# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
|
# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
|
||||||
|
|||||||
+210
-46
@@ -61,7 +61,7 @@ static RangeSet* parse_range(char* text) {
|
|||||||
|
|
||||||
RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int));
|
RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int));
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
fprintf(stderr, "failed to allocate range of %lu bytes\n",
|
fprintf(stderr, "failed to allocate range of %zu bytes\n",
|
||||||
sizeof(RangeSet) + num * sizeof(int));
|
sizeof(RangeSet) + num * sizeof(int));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -245,6 +245,133 @@ static void* unzip_new_data(void* cookie) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do a source/target load for move/bsdiff/imgdiff in version 1.
|
||||||
|
// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect
|
||||||
|
// to parse the remainder of the string as:
|
||||||
|
//
|
||||||
|
// <src_range> <tgt_range>
|
||||||
|
//
|
||||||
|
// The source range is loaded into the provided buffer, reallocating
|
||||||
|
// it to make it larger if necessary. The target ranges are returned
|
||||||
|
// in *tgt, if tgt is non-NULL.
|
||||||
|
|
||||||
|
static void LoadSrcTgtVersion1(char* wordsave, RangeSet** tgt, int* src_blocks,
|
||||||
|
uint8_t** buffer, size_t* buffer_alloc, int fd) {
|
||||||
|
char* word;
|
||||||
|
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
RangeSet* src = parse_range(word);
|
||||||
|
|
||||||
|
if (tgt != NULL) {
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
*tgt = parse_range(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
allocate(src->size * BLOCKSIZE, buffer, buffer_alloc);
|
||||||
|
size_t p = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < src->count; ++i) {
|
||||||
|
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||||
|
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
||||||
|
readblock(fd, *buffer+p, sz);
|
||||||
|
p += sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
*src_blocks = src->size;
|
||||||
|
free(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MoveRange(uint8_t* dest, RangeSet* locs, const uint8_t* source) {
|
||||||
|
// source contains packed data, which we want to move to the
|
||||||
|
// locations given in *locs in the dest buffer. source and dest
|
||||||
|
// may be the same buffer.
|
||||||
|
|
||||||
|
int start = locs->size;
|
||||||
|
int i;
|
||||||
|
for (i = locs->count-1; i >= 0; --i) {
|
||||||
|
int blocks = locs->pos[i*2+1] - locs->pos[i*2];
|
||||||
|
start -= blocks;
|
||||||
|
memmove(dest + (locs->pos[i*2] * BLOCKSIZE), source + (start * BLOCKSIZE),
|
||||||
|
blocks * BLOCKSIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a source/target load for move/bsdiff/imgdiff in version 2.
|
||||||
|
// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect
|
||||||
|
// to parse the remainder of the string as one of:
|
||||||
|
//
|
||||||
|
// <tgt_range> <src_block_count> <src_range>
|
||||||
|
// (loads data from source image only)
|
||||||
|
//
|
||||||
|
// <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
|
||||||
|
// (loads data from stashes only)
|
||||||
|
//
|
||||||
|
// <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
|
||||||
|
// (loads data from both source image and stashes)
|
||||||
|
//
|
||||||
|
// On return, buffer is filled with the loaded source data (rearranged
|
||||||
|
// and combined with stashed data as necessary). buffer may be
|
||||||
|
// reallocated if needed to accommodate the source data. *tgt is the
|
||||||
|
// target RangeSet. Any stashes required are taken from stash_table
|
||||||
|
// and free()'d after being used.
|
||||||
|
|
||||||
|
static void LoadSrcTgtVersion2(char* wordsave, RangeSet** tgt, int* src_blocks,
|
||||||
|
uint8_t** buffer, size_t* buffer_alloc, int fd,
|
||||||
|
uint8_t** stash_table) {
|
||||||
|
char* word;
|
||||||
|
|
||||||
|
if (tgt != NULL) {
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
*tgt = parse_range(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
*src_blocks = strtol(word, NULL, 0);
|
||||||
|
|
||||||
|
allocate(*src_blocks * BLOCKSIZE, buffer, buffer_alloc);
|
||||||
|
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
if (word[0] == '-' && word[1] == '\0') {
|
||||||
|
// no source ranges, only stashes
|
||||||
|
} else {
|
||||||
|
RangeSet* src = parse_range(word);
|
||||||
|
|
||||||
|
size_t p = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < src->count; ++i) {
|
||||||
|
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||||
|
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
||||||
|
readblock(fd, *buffer+p, sz);
|
||||||
|
p += sz;
|
||||||
|
}
|
||||||
|
free(src);
|
||||||
|
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
if (word == NULL) {
|
||||||
|
// no stashes, only source range
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeSet* locs = parse_range(word);
|
||||||
|
MoveRange(*buffer, locs, *buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((word = strtok_r(NULL, " ", &wordsave)) != NULL) {
|
||||||
|
// Each word is a an index into the stash table, a colon, and
|
||||||
|
// then a rangeset describing where in the source block that
|
||||||
|
// stashed data should go.
|
||||||
|
char* colonsave = NULL;
|
||||||
|
char* colon = strtok_r(word, ":", &colonsave);
|
||||||
|
int stash_id = strtol(colon, NULL, 0);
|
||||||
|
colon = strtok_r(NULL, ":", &colonsave);
|
||||||
|
RangeSet* locs = parse_range(colon);
|
||||||
|
MoveRange(*buffer, locs, stash_table[stash_id]);
|
||||||
|
free(stash_table[stash_id]);
|
||||||
|
stash_table[stash_id] = NULL;
|
||||||
|
free(locs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// args:
|
// args:
|
||||||
// - block device (or file) to modify in-place
|
// - block device (or file) to modify in-place
|
||||||
// - transfer list (blob)
|
// - transfer list (blob)
|
||||||
@@ -311,23 +438,33 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
// new [rangeset]
|
// new [rangeset]
|
||||||
// - fill the blocks with data read from the new_data file
|
// - fill the blocks with data read from the new_data file
|
||||||
//
|
//
|
||||||
// bsdiff patchstart patchlen [src rangeset] [tgt rangeset]
|
|
||||||
// imgdiff patchstart patchlen [src rangeset] [tgt rangeset]
|
|
||||||
// - read the source blocks, apply a patch, write result to
|
|
||||||
// target blocks. bsdiff or imgdiff specifies the type of
|
|
||||||
// patch.
|
|
||||||
//
|
|
||||||
// move [src rangeset] [tgt rangeset]
|
|
||||||
// - copy data from source blocks to target blocks (no patch
|
|
||||||
// needed; rangesets are the same size)
|
|
||||||
//
|
|
||||||
// erase [rangeset]
|
// erase [rangeset]
|
||||||
// - mark the given blocks as empty
|
// - mark the given blocks as empty
|
||||||
//
|
//
|
||||||
|
// move <...>
|
||||||
|
// bsdiff <patchstart> <patchlen> <...>
|
||||||
|
// imgdiff <patchstart> <patchlen> <...>
|
||||||
|
// - read the source blocks, apply a patch (or not in the
|
||||||
|
// case of move), write result to target blocks. bsdiff or
|
||||||
|
// imgdiff specifies the type of patch; move means no patch
|
||||||
|
// at all.
|
||||||
|
//
|
||||||
|
// The format of <...> differs between versions 1 and 2;
|
||||||
|
// see the LoadSrcTgtVersion{1,2}() functions for a
|
||||||
|
// description of what's expected.
|
||||||
|
//
|
||||||
|
// stash <stash_id> <src_range>
|
||||||
|
// - (version 2 only) load the given source range and stash
|
||||||
|
// the data in the given slot of the stash table.
|
||||||
|
//
|
||||||
// The creator of the transfer list will guarantee that no block
|
// The creator of the transfer list will guarantee that no block
|
||||||
// is read (ie, used as the source for a patch or move) after it
|
// is read (ie, used as the source for a patch or move) after it
|
||||||
// has been written.
|
// has been written.
|
||||||
//
|
//
|
||||||
|
// In version 2, the creator will guarantee that a given stash is
|
||||||
|
// loaded (with a stash command) before it's used in a
|
||||||
|
// move/bsdiff/imgdiff command.
|
||||||
|
//
|
||||||
// Within one command the source and target ranges may overlap so
|
// Within one command the source and target ranges may overlap so
|
||||||
// in general we need to read the entire source into memory before
|
// in general we need to read the entire source into memory before
|
||||||
// writing anything to the target blocks.
|
// writing anything to the target blocks.
|
||||||
@@ -379,12 +516,18 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
|
|
||||||
line = strtok_r(transfer_list, "\n", &linesave);
|
line = strtok_r(transfer_list, "\n", &linesave);
|
||||||
|
|
||||||
|
int version;
|
||||||
// first line in transfer list is the version number; currently
|
// first line in transfer list is the version number; currently
|
||||||
// there's only version 1.
|
// there's only version 1.
|
||||||
if (strcmp(line, "1") != 0) {
|
if (strcmp(line, "1") == 0) {
|
||||||
|
version = 1;
|
||||||
|
} else if (strcmp(line, "2") == 0) {
|
||||||
|
version = 2;
|
||||||
|
} else {
|
||||||
ErrorAbort(state, "unexpected transfer list version [%s]\n", line);
|
ErrorAbort(state, "unexpected transfer list version [%s]\n", line);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
printf("blockimg version is %d\n", version);
|
||||||
|
|
||||||
// second line in transfer list is the total number of blocks we
|
// second line in transfer list is the total number of blocks we
|
||||||
// expect to write.
|
// expect to write.
|
||||||
@@ -394,33 +537,49 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
if (total_blocks == 0) ++total_blocks;
|
if (total_blocks == 0) ++total_blocks;
|
||||||
int blocks_so_far = 0;
|
int blocks_so_far = 0;
|
||||||
|
|
||||||
|
uint8_t** stash_table = NULL;
|
||||||
|
if (version >= 2) {
|
||||||
|
// Next line is how many stash entries are needed simultaneously.
|
||||||
|
line = strtok_r(NULL, "\n", &linesave);
|
||||||
|
int stash_entries = strtol(line, NULL, 0);
|
||||||
|
|
||||||
|
stash_table = (uint8_t**) calloc(stash_entries, sizeof(uint8_t*));
|
||||||
|
if (stash_table == NULL) {
|
||||||
|
fprintf(stderr, "failed to allocate %d-entry stash table\n", stash_entries);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next line is the maximum number of blocks that will be
|
||||||
|
// stashed simultaneously. This could be used to verify that
|
||||||
|
// enough memory or scratch disk space is available.
|
||||||
|
line = strtok_r(NULL, "\n", &linesave);
|
||||||
|
int stash_max_blocks = strtol(line, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t* buffer = NULL;
|
uint8_t* buffer = NULL;
|
||||||
size_t buffer_alloc = 0;
|
size_t buffer_alloc = 0;
|
||||||
|
|
||||||
// third and subsequent lines are all individual transfer commands.
|
// third and subsequent lines are all individual transfer commands.
|
||||||
for (line = strtok_r(NULL, "\n", &linesave); line;
|
for (line = strtok_r(NULL, "\n", &linesave); line;
|
||||||
line = strtok_r(NULL, "\n", &linesave)) {
|
line = strtok_r(NULL, "\n", &linesave)) {
|
||||||
|
|
||||||
char* style;
|
char* style;
|
||||||
style = strtok_r(line, " ", &wordsave);
|
style = strtok_r(line, " ", &wordsave);
|
||||||
|
|
||||||
if (strcmp("move", style) == 0) {
|
if (strcmp("move", style) == 0) {
|
||||||
word = strtok_r(NULL, " ", &wordsave);
|
RangeSet* tgt;
|
||||||
RangeSet* src = parse_range(word);
|
int src_blocks;
|
||||||
word = strtok_r(NULL, " ", &wordsave);
|
if (version == 1) {
|
||||||
RangeSet* tgt = parse_range(word);
|
LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks,
|
||||||
|
&buffer, &buffer_alloc, fd);
|
||||||
printf(" moving %d blocks\n", src->size);
|
} else if (version == 2) {
|
||||||
|
LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks,
|
||||||
allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
|
&buffer, &buffer_alloc, fd, stash_table);
|
||||||
size_t p = 0;
|
|
||||||
for (i = 0; i < src->count; ++i) {
|
|
||||||
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
|
||||||
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
|
||||||
readblock(fd, buffer+p, sz);
|
|
||||||
p += sz;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p = 0;
|
printf(" moving %d blocks\n", src_blocks);
|
||||||
|
|
||||||
|
size_t p = 0;
|
||||||
for (i = 0; i < tgt->count; ++i) {
|
for (i = 0; i < tgt->count; ++i) {
|
||||||
check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||||
size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE;
|
size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE;
|
||||||
@@ -432,9 +591,20 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
|
fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
|
||||||
fflush(cmd_pipe);
|
fflush(cmd_pipe);
|
||||||
|
|
||||||
free(src);
|
|
||||||
free(tgt);
|
free(tgt);
|
||||||
|
|
||||||
|
} else if (strcmp("stash", style) == 0) {
|
||||||
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
|
int stash_id = strtol(word, NULL, 0);
|
||||||
|
int src_blocks;
|
||||||
|
size_t stash_alloc = 0;
|
||||||
|
|
||||||
|
// Even though the "stash" style only appears in version
|
||||||
|
// 2, the version 1 source loader happens to do exactly
|
||||||
|
// what we want to read data into the stash_table.
|
||||||
|
LoadSrcTgtVersion1(wordsave, NULL, &src_blocks,
|
||||||
|
stash_table + stash_id, &stash_alloc, fd);
|
||||||
|
|
||||||
} else if (strcmp("zero", style) == 0 ||
|
} else if (strcmp("zero", style) == 0 ||
|
||||||
(DEBUG_ERASE && strcmp("erase", style) == 0)) {
|
(DEBUG_ERASE && strcmp("erase", style) == 0)) {
|
||||||
word = strtok_r(NULL, " ", &wordsave);
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
@@ -493,23 +663,18 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
word = strtok_r(NULL, " ", &wordsave);
|
word = strtok_r(NULL, " ", &wordsave);
|
||||||
size_t patch_len = strtoul(word, NULL, 0);
|
size_t patch_len = strtoul(word, NULL, 0);
|
||||||
|
|
||||||
word = strtok_r(NULL, " ", &wordsave);
|
RangeSet* tgt;
|
||||||
RangeSet* src = parse_range(word);
|
int src_blocks;
|
||||||
word = strtok_r(NULL, " ", &wordsave);
|
if (version == 1) {
|
||||||
RangeSet* tgt = parse_range(word);
|
LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks,
|
||||||
|
&buffer, &buffer_alloc, fd);
|
||||||
printf(" patching %d blocks to %d\n", src->size, tgt->size);
|
} else if (version == 2) {
|
||||||
|
LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks,
|
||||||
// Read the source into memory.
|
&buffer, &buffer_alloc, fd, stash_table);
|
||||||
allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
|
|
||||||
size_t p = 0;
|
|
||||||
for (i = 0; i < src->count; ++i) {
|
|
||||||
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
|
||||||
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
|
||||||
readblock(fd, buffer+p, sz);
|
|
||||||
p += sz;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf(" patching %d blocks to %d\n", src_blocks, tgt->size);
|
||||||
|
|
||||||
Value patch_value;
|
Value patch_value;
|
||||||
patch_value.type = VAL_BLOB;
|
patch_value.type = VAL_BLOB;
|
||||||
patch_value.size = patch_len;
|
patch_value.size = patch_len;
|
||||||
@@ -523,11 +688,11 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
|
check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
|
||||||
|
|
||||||
if (style[0] == 'i') { // imgdiff
|
if (style[0] == 'i') { // imgdiff
|
||||||
ApplyImagePatch(buffer, src->size * BLOCKSIZE,
|
ApplyImagePatch(buffer, src_blocks * BLOCKSIZE,
|
||||||
&patch_value,
|
&patch_value,
|
||||||
&RangeSinkWrite, &rss, NULL, NULL);
|
&RangeSinkWrite, &rss, NULL, NULL);
|
||||||
} else {
|
} else {
|
||||||
ApplyBSDiffPatch(buffer, src->size * BLOCKSIZE,
|
ApplyBSDiffPatch(buffer, src_blocks * BLOCKSIZE,
|
||||||
&patch_value, 0,
|
&patch_value, 0,
|
||||||
&RangeSinkWrite, &rss, NULL);
|
&RangeSinkWrite, &rss, NULL);
|
||||||
}
|
}
|
||||||
@@ -541,7 +706,6 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
|||||||
fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
|
fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
|
||||||
fflush(cmd_pipe);
|
fflush(cmd_pipe);
|
||||||
|
|
||||||
free(src);
|
|
||||||
free(tgt);
|
free(tgt);
|
||||||
} else if (!DEBUG_ERASE && strcmp("erase", style) == 0) {
|
} else if (!DEBUG_ERASE && strcmp("erase", style) == 0) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|||||||
+120
-52
@@ -46,12 +46,33 @@
|
|||||||
#include "mtdutils/mtdutils.h"
|
#include "mtdutils/mtdutils.h"
|
||||||
#include "updater.h"
|
#include "updater.h"
|
||||||
#include "install.h"
|
#include "install.h"
|
||||||
|
#include "tune2fs.h"
|
||||||
|
|
||||||
#ifdef USE_EXT4
|
#ifdef USE_EXT4
|
||||||
#include "make_ext4fs.h"
|
#include "make_ext4fs.h"
|
||||||
#include "wipe.h"
|
#include "wipe.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void uiPrint(State* state, char* buffer) {
|
||||||
|
char* line = strtok(buffer, "\n");
|
||||||
|
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
|
||||||
|
while (line) {
|
||||||
|
fprintf(ui->cmd_pipe, "ui_print %s\n", line);
|
||||||
|
line = strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
fprintf(ui->cmd_pipe, "ui_print\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((__format__(printf, 2, 3))) __nonnull((2))
|
||||||
|
void uiPrintf(State* state, const char* format, ...) {
|
||||||
|
char error_msg[1024];
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
vsnprintf(error_msg, sizeof(error_msg), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
uiPrint(state, error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
// Take a sha-1 digest and return it as a newly-allocated hex string.
|
// Take a sha-1 digest and return it as a newly-allocated hex string.
|
||||||
char* PrintSha1(const uint8_t* digest) {
|
char* PrintSha1(const uint8_t* digest) {
|
||||||
char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
|
char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
|
||||||
@@ -71,16 +92,27 @@ char* PrintSha1(const uint8_t* digest) {
|
|||||||
// fs_type="ext4" partition_type="EMMC" location=device
|
// fs_type="ext4" partition_type="EMMC" location=device
|
||||||
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
char* result = NULL;
|
char* result = NULL;
|
||||||
if (argc != 4) {
|
if (argc != 4 && argc != 5) {
|
||||||
return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
|
return ErrorAbort(state, "%s() expects 4-5 args, got %d", name, argc);
|
||||||
}
|
}
|
||||||
char* fs_type;
|
char* fs_type;
|
||||||
char* partition_type;
|
char* partition_type;
|
||||||
char* location;
|
char* location;
|
||||||
char* mount_point;
|
char* mount_point;
|
||||||
if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
|
char* mount_options;
|
||||||
|
bool has_mount_options;
|
||||||
|
if (argc == 5) {
|
||||||
|
has_mount_options = true;
|
||||||
|
if (ReadArgs(state, argv, 5, &fs_type, &partition_type,
|
||||||
|
&location, &mount_point, &mount_options) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
has_mount_options = false;
|
||||||
|
if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
|
||||||
&location, &mount_point) < 0) {
|
&location, &mount_point) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(fs_type) == 0) {
|
if (strlen(fs_type) == 0) {
|
||||||
@@ -120,13 +152,13 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
const MtdPartition* mtd;
|
const MtdPartition* mtd;
|
||||||
mtd = mtd_find_partition_by_name(location);
|
mtd = mtd_find_partition_by_name(location);
|
||||||
if (mtd == NULL) {
|
if (mtd == NULL) {
|
||||||
printf("%s: no mtd partition named \"%s\"",
|
uiPrintf(state, "%s: no mtd partition named \"%s\"",
|
||||||
name, location);
|
name, location);
|
||||||
result = strdup("");
|
result = strdup("");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
|
if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
|
||||||
printf("mtd mount of %s failed: %s\n",
|
uiPrintf(state, "mtd mount of %s failed: %s\n",
|
||||||
location, strerror(errno));
|
location, strerror(errno));
|
||||||
result = strdup("");
|
result = strdup("");
|
||||||
goto done;
|
goto done;
|
||||||
@@ -134,8 +166,9 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
result = mount_point;
|
result = mount_point;
|
||||||
} else {
|
} else {
|
||||||
if (mount(location, mount_point, fs_type,
|
if (mount(location, mount_point, fs_type,
|
||||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
|
MS_NOATIME | MS_NODEV | MS_NODIRATIME,
|
||||||
printf("%s: failed to mount %s at %s: %s\n",
|
has_mount_options ? mount_options : "") < 0) {
|
||||||
|
uiPrintf(state, "%s: failed to mount %s at %s: %s\n",
|
||||||
name, location, mount_point, strerror(errno));
|
name, location, mount_point, strerror(errno));
|
||||||
result = strdup("");
|
result = strdup("");
|
||||||
} else {
|
} else {
|
||||||
@@ -148,6 +181,7 @@ done:
|
|||||||
free(partition_type);
|
free(partition_type);
|
||||||
free(location);
|
free(location);
|
||||||
if (result != mount_point) free(mount_point);
|
if (result != mount_point) free(mount_point);
|
||||||
|
if (has_mount_options) free(mount_options);
|
||||||
return StringValue(result);
|
return StringValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,10 +232,14 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
scan_mounted_volumes();
|
scan_mounted_volumes();
|
||||||
const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
|
const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point);
|
||||||
if (vol == NULL) {
|
if (vol == NULL) {
|
||||||
printf("unmount of %s failed; no such volume\n", mount_point);
|
uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point);
|
||||||
result = strdup("");
|
result = strdup("");
|
||||||
} else {
|
} else {
|
||||||
unmount_mounted_volume(vol);
|
int ret = unmount_mounted_volume(vol);
|
||||||
|
if (ret != 0) {
|
||||||
|
uiPrintf(state, "unmount of %s failed (%d): %s\n",
|
||||||
|
mount_point, ret, strerror(errno));
|
||||||
|
}
|
||||||
result = mount_point;
|
result = mount_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,6 +396,9 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
if (make_parents(dst_name) != 0) {
|
if (make_parents(dst_name) != 0) {
|
||||||
ErrorAbort(state, "Creating parent of %s failed, error %s",
|
ErrorAbort(state, "Creating parent of %s failed, error %s",
|
||||||
dst_name, strerror(errno));
|
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) {
|
} else if (rename(src_name, dst_name) != 0) {
|
||||||
ErrorAbort(state, "Rename of %s to %s failed, error %s",
|
ErrorAbort(state, "Rename of %s to %s failed, error %s",
|
||||||
src_name, dst_name, strerror(errno));
|
src_name, dst_name, strerror(errno));
|
||||||
@@ -630,7 +671,7 @@ struct perm_parsed_args {
|
|||||||
uint64_t capabilities;
|
uint64_t capabilities;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
static struct perm_parsed_args ParsePermArgs(State * state, int argc, char** args) {
|
||||||
int i;
|
int i;
|
||||||
struct perm_parsed_args parsed;
|
struct perm_parsed_args parsed;
|
||||||
int bad = 0;
|
int bad = 0;
|
||||||
@@ -645,7 +686,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.uid = uid;
|
parsed.uid = uid;
|
||||||
parsed.has_uid = true;
|
parsed.has_uid = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -656,7 +697,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.gid = gid;
|
parsed.gid = gid;
|
||||||
parsed.has_gid = true;
|
parsed.has_gid = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -667,7 +708,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.mode = mode;
|
parsed.mode = mode;
|
||||||
parsed.has_mode = true;
|
parsed.has_mode = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -678,7 +719,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.dmode = mode;
|
parsed.dmode = mode;
|
||||||
parsed.has_dmode = true;
|
parsed.has_dmode = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -689,7 +730,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.fmode = mode;
|
parsed.fmode = mode;
|
||||||
parsed.has_fmode = true;
|
parsed.has_fmode = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -700,7 +741,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.capabilities = capabilities;
|
parsed.capabilities = capabilities;
|
||||||
parsed.has_capabilities = true;
|
parsed.has_capabilities = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -710,7 +751,7 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
parsed.selabel = args[i+1];
|
parsed.selabel = args[i+1];
|
||||||
parsed.has_selabel = true;
|
parsed.has_selabel = true;
|
||||||
} else {
|
} else {
|
||||||
printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]);
|
uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]);
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -727,71 +768,71 @@ static struct perm_parsed_args ParsePermArgs(int argc, char** args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ApplyParsedPerms(
|
static int ApplyParsedPerms(
|
||||||
|
State * state,
|
||||||
const char* filename,
|
const char* filename,
|
||||||
const struct stat *statptr,
|
const struct stat *statptr,
|
||||||
struct perm_parsed_args parsed)
|
struct perm_parsed_args parsed)
|
||||||
{
|
{
|
||||||
int bad = 0;
|
int bad = 0;
|
||||||
|
|
||||||
|
if (parsed.has_selabel) {
|
||||||
|
if (lsetfilecon(filename, parsed.selabel) != 0) {
|
||||||
|
uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n",
|
||||||
|
filename, parsed.selabel, strerror(errno));
|
||||||
|
bad++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ignore symlinks */
|
/* ignore symlinks */
|
||||||
if (S_ISLNK(statptr->st_mode)) {
|
if (S_ISLNK(statptr->st_mode)) {
|
||||||
return 0;
|
return bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.has_uid) {
|
if (parsed.has_uid) {
|
||||||
if (chown(filename, parsed.uid, -1) < 0) {
|
if (chown(filename, parsed.uid, -1) < 0) {
|
||||||
printf("ApplyParsedPerms: chown of %s to %d failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n",
|
||||||
filename, parsed.uid, strerror(errno));
|
filename, parsed.uid, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.has_gid) {
|
if (parsed.has_gid) {
|
||||||
if (chown(filename, -1, parsed.gid) < 0) {
|
if (chown(filename, -1, parsed.gid) < 0) {
|
||||||
printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n",
|
||||||
filename, parsed.gid, strerror(errno));
|
filename, parsed.gid, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.has_mode) {
|
if (parsed.has_mode) {
|
||||||
if (chmod(filename, parsed.mode) < 0) {
|
if (chmod(filename, parsed.mode) < 0) {
|
||||||
printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n",
|
||||||
filename, parsed.mode, strerror(errno));
|
filename, parsed.mode, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) {
|
if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) {
|
||||||
if (chmod(filename, parsed.dmode) < 0) {
|
if (chmod(filename, parsed.dmode) < 0) {
|
||||||
printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n",
|
||||||
filename, parsed.dmode, strerror(errno));
|
filename, parsed.dmode, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.has_fmode && S_ISREG(statptr->st_mode)) {
|
if (parsed.has_fmode && S_ISREG(statptr->st_mode)) {
|
||||||
if (chmod(filename, parsed.fmode) < 0) {
|
if (chmod(filename, parsed.fmode) < 0) {
|
||||||
printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n",
|
||||||
filename, parsed.fmode, strerror(errno));
|
filename, parsed.fmode, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.has_selabel) {
|
|
||||||
// TODO: Don't silently ignore ENOTSUP
|
|
||||||
if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) {
|
|
||||||
printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n",
|
|
||||||
filename, parsed.selabel, strerror(errno));
|
|
||||||
bad++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) {
|
if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) {
|
||||||
if (parsed.capabilities == 0) {
|
if (parsed.capabilities == 0) {
|
||||||
if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) {
|
if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) {
|
||||||
// Report failure unless it's ENODATA (attribute not set)
|
// Report failure unless it's ENODATA (attribute not set)
|
||||||
printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n",
|
||||||
filename, parsed.capabilities, strerror(errno));
|
filename, parsed.capabilities, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
@@ -804,8 +845,8 @@ static int ApplyParsedPerms(
|
|||||||
cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32);
|
cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32);
|
||||||
cap_data.data[1].inheritable = 0;
|
cap_data.data[1].inheritable = 0;
|
||||||
if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) {
|
if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) {
|
||||||
printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n",
|
uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n",
|
||||||
filename, parsed.capabilities, strerror(errno));
|
filename, parsed.capabilities, strerror(errno));
|
||||||
bad++;
|
bad++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -817,10 +858,11 @@ static int ApplyParsedPerms(
|
|||||||
// nftw doesn't allow us to pass along context, so we need to use
|
// nftw doesn't allow us to pass along context, so we need to use
|
||||||
// global variables. *sigh*
|
// global variables. *sigh*
|
||||||
static struct perm_parsed_args recursive_parsed_args;
|
static struct perm_parsed_args recursive_parsed_args;
|
||||||
|
static State* recursive_state;
|
||||||
|
|
||||||
static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr,
|
static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr,
|
||||||
int fileflags, struct FTW *pfwt) {
|
int fileflags, struct FTW *pfwt) {
|
||||||
return ApplyParsedPerms(filename, statptr, recursive_parsed_args);
|
return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) {
|
static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
@@ -845,14 +887,16 @@ static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct perm_parsed_args parsed = ParsePermArgs(argc, args);
|
struct perm_parsed_args parsed = ParsePermArgs(state, argc, args);
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
recursive_parsed_args = parsed;
|
recursive_parsed_args = parsed;
|
||||||
|
recursive_state = state;
|
||||||
bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS);
|
bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS);
|
||||||
memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args));
|
memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args));
|
||||||
|
recursive_state = NULL;
|
||||||
} else {
|
} else {
|
||||||
bad += ApplyParsedPerms(args[0], &sb, parsed);
|
bad += ApplyParsedPerms(state, args[0], &sb, parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@@ -1224,15 +1268,7 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
}
|
}
|
||||||
free(args);
|
free(args);
|
||||||
buffer[size] = '\0';
|
buffer[size] = '\0';
|
||||||
|
uiPrint(state, buffer);
|
||||||
char* line = strtok(buffer, "\n");
|
|
||||||
while (line) {
|
|
||||||
fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe,
|
|
||||||
"ui_print %s\n", line);
|
|
||||||
line = strtok(NULL, "\n");
|
|
||||||
}
|
|
||||||
fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "ui_print\n");
|
|
||||||
|
|
||||||
return StringValue(buffer);
|
return StringValue(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1504,6 +1540,37 @@ Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
return StringValue(strdup("t"));
|
return StringValue(strdup("t"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
|
if (argc == 0) {
|
||||||
|
return ErrorAbort(state, "%s() expects args, got %d", name, argc);
|
||||||
|
}
|
||||||
|
|
||||||
|
char** args = ReadVarArgs(state, argc, argv);
|
||||||
|
if (args == NULL) {
|
||||||
|
return ErrorAbort(state, "%s() could not read args", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
char** args2 = malloc(sizeof(char*) * (argc+1));
|
||||||
|
// Tune2fs expects the program name as its args[0]
|
||||||
|
args2[0] = strdup(name);
|
||||||
|
for (i = 0; i < argc; ++i) {
|
||||||
|
args2[i + 1] = args[i];
|
||||||
|
}
|
||||||
|
int result = tune2fs_main(argc + 1, args2);
|
||||||
|
for (i = 0; i < argc; ++i) {
|
||||||
|
free(args[i]);
|
||||||
|
}
|
||||||
|
free(args);
|
||||||
|
|
||||||
|
free(args2[0]);
|
||||||
|
free(args2);
|
||||||
|
if (result != 0) {
|
||||||
|
return ErrorAbort(state, "%s() returned error code %d", name, result);
|
||||||
|
}
|
||||||
|
return StringValue(strdup("t"));
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterInstallFunctions() {
|
void RegisterInstallFunctions() {
|
||||||
RegisterFunction("mount", MountFn);
|
RegisterFunction("mount", MountFn);
|
||||||
RegisterFunction("is_mounted", IsMountedFn);
|
RegisterFunction("is_mounted", IsMountedFn);
|
||||||
@@ -1554,4 +1621,5 @@ void RegisterInstallFunctions() {
|
|||||||
RegisterFunction("set_stage", SetStageFn);
|
RegisterFunction("set_stage", SetStageFn);
|
||||||
|
|
||||||
RegisterFunction("enable_reboot", EnableRebootFn);
|
RegisterFunction("enable_reboot", EnableRebootFn);
|
||||||
|
RegisterFunction("tune2fs", Tune2FsFn);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user