Merge commit '25c2b2f670a3b11f7ce78eccde10c1a79188c9a8' into HEAD
This commit is contained in:
+3
-15
@@ -424,20 +424,18 @@ 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 | O_SYNC);
|
int fd = open(partition, O_RDWR);
|
||||||
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;
|
||||||
}
|
}
|
||||||
int attempt;
|
int attempt;
|
||||||
|
|
||||||
for (attempt = 0; attempt < 10; ++attempt) {
|
for (attempt = 0; attempt < 2; ++attempt) {
|
||||||
size_t next_sync = start + (1<<20);
|
|
||||||
printf("raw O_SYNC write %s attempt %d start at %d\n", partition, attempt+1, start);
|
|
||||||
lseek(fd, start, SEEK_SET);
|
lseek(fd, start, SEEK_SET);
|
||||||
while (start < len) {
|
while (start < len) {
|
||||||
size_t to_write = len - start;
|
size_t to_write = len - start;
|
||||||
if (to_write > 4096) to_write = 4096;
|
if (to_write > 1<<20) to_write = 1<<20;
|
||||||
|
|
||||||
ssize_t written = write(fd, data+start, to_write);
|
ssize_t written = write(fd, data+start, to_write);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
@@ -450,10 +448,6 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
start += written;
|
start += written;
|
||||||
if (start >= next_sync) {
|
|
||||||
fsync(fd);
|
|
||||||
next_sync = start + (1<<20);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fsync(fd);
|
fsync(fd);
|
||||||
|
|
||||||
@@ -506,8 +500,6 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -519,11 +511,7 @@ int WriteToPartition(unsigned char* data, size_t len,
|
|||||||
printf("error closing %s (%s)\n", partition, strerror(errno));
|
printf("error closing %s (%s)\n", partition, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// hack: sync and sleep after closing in hopes of getting
|
|
||||||
// the data actually onto flash.
|
|
||||||
printf("sleeping after close\n");
|
|
||||||
sync();
|
sync();
|
||||||
sleep(5);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-1
@@ -38,11 +38,24 @@ extern "C" {
|
|||||||
* The recovery field is only written by linux and used
|
* The recovery field is only written by linux and used
|
||||||
* for the system to send a message to recovery or the
|
* for the system to send a message to recovery or the
|
||||||
* other way around.
|
* other way around.
|
||||||
|
*
|
||||||
|
* The stage field is written by packages which restart themselves
|
||||||
|
* multiple times, so that the UI can reflect which invocation of the
|
||||||
|
* package it is. If the value is of the format "#/#" (eg, "1/3"),
|
||||||
|
* the UI will add a simple indicator of that status.
|
||||||
*/
|
*/
|
||||||
struct bootloader_message {
|
struct bootloader_message {
|
||||||
char command[32];
|
char command[32];
|
||||||
char status[32];
|
char status[32];
|
||||||
char recovery[1024];
|
char recovery[768];
|
||||||
|
|
||||||
|
// The 'recovery' field used to be 1024 bytes. It has only ever
|
||||||
|
// been used to store the recovery command line, so 768 bytes
|
||||||
|
// should be plenty. We carve off the last 256 bytes to store the
|
||||||
|
// stage string (for multistage packages) and possible future
|
||||||
|
// expansion.
|
||||||
|
char stage[32];
|
||||||
|
char reserved[224];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Read and write the bootloader command from the "misc" partition.
|
/* Read and write the bootloader command from the "misc" partition.
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ static const struct option OPTIONS[] = {
|
|||||||
{ "show_text", no_argument, NULL, 't' },
|
{ "show_text", no_argument, NULL, 't' },
|
||||||
{ "just_exit", no_argument, NULL, 'x' },
|
{ "just_exit", no_argument, NULL, 'x' },
|
||||||
{ "locale", required_argument, NULL, 'l' },
|
{ "locale", required_argument, NULL, 'l' },
|
||||||
|
{ "stages", required_argument, NULL, 'g' },
|
||||||
{ "shutdown_after", no_argument, NULL, 'p' },
|
{ "shutdown_after", no_argument, NULL, 'p' },
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
@@ -77,6 +78,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
|
|||||||
RecoveryUI* ui = NULL;
|
RecoveryUI* ui = NULL;
|
||||||
char* locale = NULL;
|
char* locale = NULL;
|
||||||
char recovery_version[PROPERTY_VALUE_MAX+1];
|
char recovery_version[PROPERTY_VALUE_MAX+1];
|
||||||
|
char* stage = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The recovery tool communicates with the main system through /cache files.
|
* The recovery tool communicates with the main system through /cache files.
|
||||||
@@ -173,6 +175,7 @@ get_args(int *argc, char ***argv) {
|
|||||||
struct bootloader_message boot;
|
struct bootloader_message boot;
|
||||||
memset(&boot, 0, sizeof(boot));
|
memset(&boot, 0, sizeof(boot));
|
||||||
get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
|
get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
|
||||||
|
stage = strndup(boot.stage, sizeof(boot.stage));
|
||||||
|
|
||||||
if (boot.command[0] != 0 && boot.command[0] != 255) {
|
if (boot.command[0] != 0 && boot.command[0] != 255) {
|
||||||
LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
|
LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
|
||||||
@@ -959,6 +962,14 @@ main(int argc, char **argv) {
|
|||||||
case 't': show_text = 1; break;
|
case 't': show_text = 1; break;
|
||||||
case 'x': just_exit = true; break;
|
case 'x': just_exit = true; break;
|
||||||
case 'l': locale = optarg; break;
|
case 'l': locale = optarg; break;
|
||||||
|
case 'g': {
|
||||||
|
if (stage == NULL || *stage == '\0') {
|
||||||
|
char buffer[20] = "1/";
|
||||||
|
strncat(buffer, optarg, sizeof(buffer)-3);
|
||||||
|
stage = strdup(buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'p': shutdown_after = true; break;
|
case 'p': shutdown_after = true; break;
|
||||||
case '?':
|
case '?':
|
||||||
LOGE("Invalid command argument\n");
|
LOGE("Invalid command argument\n");
|
||||||
@@ -970,6 +981,7 @@ main(int argc, char **argv) {
|
|||||||
load_locale_from_cache();
|
load_locale_from_cache();
|
||||||
}
|
}
|
||||||
printf("locale is [%s]\n", locale);
|
printf("locale is [%s]\n", locale);
|
||||||
|
printf("stage is [%s]\n", stage, stage);
|
||||||
|
|
||||||
Device* device = make_device();
|
Device* device = make_device();
|
||||||
ui = device->GetUI();
|
ui = device->GetUI();
|
||||||
@@ -977,6 +989,12 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
ui->SetLocale(locale);
|
ui->SetLocale(locale);
|
||||||
ui->Init();
|
ui->Init();
|
||||||
|
|
||||||
|
int st_cur, st_max;
|
||||||
|
if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) {
|
||||||
|
ui->SetStage(st_cur, st_max);
|
||||||
|
}
|
||||||
|
|
||||||
ui->SetBackground(RecoveryUI::NONE);
|
ui->SetBackground(RecoveryUI::NONE);
|
||||||
if (show_text) ui->ShowText(true);
|
if (show_text) ui->ShowText(true);
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 322 B |
Binary file not shown.
|
After Width: | Height: | Size: 258 B |
+28
-3
@@ -71,7 +71,9 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
|
|||||||
menu_items(0),
|
menu_items(0),
|
||||||
menu_sel(0),
|
menu_sel(0),
|
||||||
animation_fps(20),
|
animation_fps(20),
|
||||||
installing_frames(-1) {
|
installing_frames(-1),
|
||||||
|
stage(-1),
|
||||||
|
max_stage(-1) {
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
backgroundIcon[i] = NULL;
|
backgroundIcon[i] = NULL;
|
||||||
|
|
||||||
@@ -98,15 +100,29 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon)
|
|||||||
int iconHeight = gr_get_height(surface);
|
int iconHeight = gr_get_height(surface);
|
||||||
int textWidth = gr_get_width(text_surface);
|
int textWidth = gr_get_width(text_surface);
|
||||||
int textHeight = gr_get_height(text_surface);
|
int textHeight = gr_get_height(text_surface);
|
||||||
|
int stageHeight = gr_get_height(stageMarkerEmpty);
|
||||||
|
|
||||||
|
int sh = (max_stage >= 0) ? stageHeight : 0;
|
||||||
|
|
||||||
iconX = (gr_fb_width() - iconWidth) / 2;
|
iconX = (gr_fb_width() - iconWidth) / 2;
|
||||||
iconY = (gr_fb_height() - (iconHeight+textHeight+40)) / 2;
|
iconY = (gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2;
|
||||||
|
|
||||||
int textX = (gr_fb_width() - textWidth) / 2;
|
int textX = (gr_fb_width() - textWidth) / 2;
|
||||||
int textY = ((gr_fb_height() - (iconHeight+textHeight+40)) / 2) + iconHeight + 40;
|
int textY = ((gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2) + iconHeight + 40;
|
||||||
|
|
||||||
gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
|
gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
|
||||||
|
|
||||||
|
if (stageHeight > 0) {
|
||||||
|
int sw = gr_get_width(stageMarkerEmpty);
|
||||||
|
int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
|
||||||
|
int y = iconY + iconHeight + 20;
|
||||||
|
for (int i = 0; i < max_stage; ++i) {
|
||||||
|
gr_blit((i < stage) ? stageMarkerFill : stageMarkerEmpty,
|
||||||
|
0, 0, sw, stageHeight, x, y);
|
||||||
|
x += sw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gr_color(255, 255, 255, 255);
|
gr_color(255, 255, 255, 255);
|
||||||
gr_texticon(textX, textY, text_surface);
|
gr_texticon(textX, textY, text_surface);
|
||||||
}
|
}
|
||||||
@@ -350,6 +366,8 @@ void ScreenRecoveryUI::Init()
|
|||||||
|
|
||||||
LoadBitmap("progress_empty", &progressBarEmpty);
|
LoadBitmap("progress_empty", &progressBarEmpty);
|
||||||
LoadBitmap("progress_fill", &progressBarFill);
|
LoadBitmap("progress_fill", &progressBarFill);
|
||||||
|
LoadBitmap("stage_empty", &stageMarkerEmpty);
|
||||||
|
LoadBitmap("stage_fill", &stageMarkerFill);
|
||||||
|
|
||||||
LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
|
LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
|
||||||
LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
|
LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
|
||||||
@@ -440,6 +458,13 @@ void ScreenRecoveryUI::SetProgress(float fraction)
|
|||||||
pthread_mutex_unlock(&updateMutex);
|
pthread_mutex_unlock(&updateMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenRecoveryUI::SetStage(int current, int max) {
|
||||||
|
pthread_mutex_lock(&updateMutex);
|
||||||
|
stage = current;
|
||||||
|
max_stage = max;
|
||||||
|
pthread_mutex_unlock(&updateMutex);
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenRecoveryUI::Print(const char *fmt, ...)
|
void ScreenRecoveryUI::Print(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|||||||
+6
-4
@@ -39,6 +39,8 @@ class ScreenRecoveryUI : public RecoveryUI {
|
|||||||
void ShowProgress(float portion, float seconds);
|
void ShowProgress(float portion, float seconds);
|
||||||
void SetProgress(float fraction);
|
void SetProgress(float fraction);
|
||||||
|
|
||||||
|
void SetStage(int current, int max);
|
||||||
|
|
||||||
// text log
|
// text log
|
||||||
void ShowText(bool visible);
|
void ShowText(bool visible);
|
||||||
bool IsTextVisible();
|
bool IsTextVisible();
|
||||||
@@ -58,9 +60,6 @@ class ScreenRecoveryUI : public RecoveryUI {
|
|||||||
enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL };
|
enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL };
|
||||||
virtual void SetColor(UIElement e);
|
virtual void SetColor(UIElement e);
|
||||||
|
|
||||||
protected:
|
|
||||||
int install_overlay_offset_x, install_overlay_offset_y;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Icon currentIcon;
|
Icon currentIcon;
|
||||||
int installingFrame;
|
int installingFrame;
|
||||||
@@ -73,6 +72,8 @@ class ScreenRecoveryUI : public RecoveryUI {
|
|||||||
gr_surface *installation;
|
gr_surface *installation;
|
||||||
gr_surface progressBarEmpty;
|
gr_surface progressBarEmpty;
|
||||||
gr_surface progressBarFill;
|
gr_surface progressBarFill;
|
||||||
|
gr_surface stageMarkerEmpty;
|
||||||
|
gr_surface stageMarkerFill;
|
||||||
|
|
||||||
ProgressType progressBarType;
|
ProgressType progressBarType;
|
||||||
|
|
||||||
@@ -104,7 +105,8 @@ class ScreenRecoveryUI : public RecoveryUI {
|
|||||||
|
|
||||||
int iconX, iconY;
|
int iconX, iconY;
|
||||||
|
|
||||||
void draw_install_overlay_locked(int frame);
|
int stage, max_stage;
|
||||||
|
|
||||||
void draw_background_locked(Icon icon);
|
void draw_background_locked(Icon icon);
|
||||||
void draw_progress_locked();
|
void draw_progress_locked();
|
||||||
void draw_screen_locked();
|
void draw_screen_locked();
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class RecoveryUI {
|
|||||||
|
|
||||||
// Initialize the object; called before anything else.
|
// Initialize the object; called before anything else.
|
||||||
virtual void Init();
|
virtual void Init();
|
||||||
|
// Show a stage indicator. Call immediately after Init().
|
||||||
|
virtual void SetStage(int current, int max) { }
|
||||||
|
|
||||||
// After calling Init(), you can tell the UI what locale it is operating in.
|
// After calling Init(), you can tell the UI what locale it is operating in.
|
||||||
virtual void SetLocale(const char* locale) { }
|
virtual void SetLocale(const char* locale) { }
|
||||||
|
|||||||
+109
-6
@@ -34,6 +34,9 @@
|
|||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "bootloader.h"
|
||||||
|
#include "applypatch/applypatch.h"
|
||||||
|
#include "cutils/android_reboot.h"
|
||||||
#include "cutils/misc.h"
|
#include "cutils/misc.h"
|
||||||
#include "cutils/properties.h"
|
#include "cutils/properties.h"
|
||||||
#include "edify/expr.h"
|
#include "edify/expr.h"
|
||||||
@@ -42,7 +45,6 @@
|
|||||||
#include "mtdutils/mounts.h"
|
#include "mtdutils/mounts.h"
|
||||||
#include "mtdutils/mtdutils.h"
|
#include "mtdutils/mtdutils.h"
|
||||||
#include "updater.h"
|
#include "updater.h"
|
||||||
#include "applypatch/applypatch.h"
|
|
||||||
|
|
||||||
#ifdef USE_EXT4
|
#ifdef USE_EXT4
|
||||||
#include "make_ext4fs.h"
|
#include "make_ext4fs.h"
|
||||||
@@ -1269,7 +1271,6 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args[0]->size < 0) {
|
if (args[0]->size < 0) {
|
||||||
printf("%s(): no file contents received", name);
|
|
||||||
return StringValue(strdup(""));
|
return StringValue(strdup(""));
|
||||||
}
|
}
|
||||||
uint8_t digest[SHA_DIGEST_SIZE];
|
uint8_t digest[SHA_DIGEST_SIZE];
|
||||||
@@ -1322,12 +1323,11 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
|
|
||||||
FileContents fc;
|
FileContents fc;
|
||||||
if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
|
if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
|
||||||
ErrorAbort(state, "%s() loading \"%s\" failed: %s",
|
|
||||||
name, filename, strerror(errno));
|
|
||||||
free(filename);
|
free(filename);
|
||||||
free(v);
|
v->size = -1;
|
||||||
|
v->data = NULL;
|
||||||
free(fc.data);
|
free(fc.data);
|
||||||
return NULL;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
v->size = fc.size;
|
v->size = fc.size;
|
||||||
@@ -1337,6 +1337,105 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Immediately reboot the device. Recovery is not finished normally,
|
||||||
|
// so if you reboot into recovery it will re-start applying the
|
||||||
|
// current package (because nothing has cleared the copy of the
|
||||||
|
// arguments stored in the BCB).
|
||||||
|
//
|
||||||
|
// The argument is the partition name passed to the android reboot
|
||||||
|
// property. It can be "recovery" to boot from the recovery
|
||||||
|
// partition, or "" (empty string) to boot from the regular boot
|
||||||
|
// partition.
|
||||||
|
Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filename;
|
||||||
|
char* property;
|
||||||
|
if (ReadArgs(state, argv, 2, &filename, &property) < 0) return NULL;
|
||||||
|
|
||||||
|
char buffer[80];
|
||||||
|
|
||||||
|
// zero out the 'command' field of the bootloader message.
|
||||||
|
memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command));
|
||||||
|
FILE* f = fopen(filename, "r+b");
|
||||||
|
fseek(f, offsetof(struct bootloader_message, command), SEEK_SET);
|
||||||
|
fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
|
||||||
|
fclose(f);
|
||||||
|
free(filename);
|
||||||
|
|
||||||
|
strcpy(buffer, "reboot,");
|
||||||
|
if (property != NULL) {
|
||||||
|
strncat(buffer, property, sizeof(buffer)-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
property_set(ANDROID_RB_PROPERTY, buffer);
|
||||||
|
|
||||||
|
sleep(5);
|
||||||
|
free(property);
|
||||||
|
ErrorAbort(state, "%s() failed to reboot", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store a string value somewhere that future invocations of recovery
|
||||||
|
// can access it. This value is called the "stage" and can be used to
|
||||||
|
// drive packages that need to do reboots in the middle of
|
||||||
|
// installation and keep track of where they are in the multi-stage
|
||||||
|
// install.
|
||||||
|
//
|
||||||
|
// The first argument is the block device for the misc partition
|
||||||
|
// ("/misc" in the fstab), which is where this value is stored. The
|
||||||
|
// second argument is the string to store; it should not exceed 31
|
||||||
|
// bytes.
|
||||||
|
Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filename;
|
||||||
|
char* stagestr;
|
||||||
|
if (ReadArgs(state, argv, 2, &filename, &stagestr) < 0) return NULL;
|
||||||
|
|
||||||
|
// Store this value in the misc partition, immediately after the
|
||||||
|
// bootloader message that the main recovery uses to save its
|
||||||
|
// arguments in case of the device restarting midway through
|
||||||
|
// package installation.
|
||||||
|
FILE* f = fopen(filename, "r+b");
|
||||||
|
fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
|
||||||
|
int to_write = strlen(stagestr)+1;
|
||||||
|
int max_size = sizeof(((struct bootloader_message*)0)->stage);
|
||||||
|
if (to_write > max_size) {
|
||||||
|
to_write = max_size;
|
||||||
|
stagestr[max_size-1] = 0;
|
||||||
|
}
|
||||||
|
fwrite(stagestr, to_write, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
free(stagestr);
|
||||||
|
return StringValue(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the value most recently saved with SetStageFn. The argument
|
||||||
|
// is the block device for the misc partition.
|
||||||
|
Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filename;
|
||||||
|
if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
|
||||||
|
|
||||||
|
char buffer[sizeof(((struct bootloader_message*)0)->stage)];
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
|
||||||
|
fread(buffer, sizeof(buffer), 1, f);
|
||||||
|
fclose(f);
|
||||||
|
buffer[sizeof(buffer)-1] = '\0';
|
||||||
|
|
||||||
|
return StringValue(strdup(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterInstallFunctions() {
|
void RegisterInstallFunctions() {
|
||||||
RegisterFunction("mount", MountFn);
|
RegisterFunction("mount", MountFn);
|
||||||
RegisterFunction("is_mounted", IsMountedFn);
|
RegisterFunction("is_mounted", IsMountedFn);
|
||||||
@@ -1379,4 +1478,8 @@ void RegisterInstallFunctions() {
|
|||||||
RegisterFunction("ui_print", UIPrintFn);
|
RegisterFunction("ui_print", UIPrintFn);
|
||||||
|
|
||||||
RegisterFunction("run_program", RunProgramFn);
|
RegisterFunction("run_program", RunProgramFn);
|
||||||
|
|
||||||
|
RegisterFunction("reboot_now", RebootNowFn);
|
||||||
|
RegisterFunction("get_stage", GetStageFn);
|
||||||
|
RegisterFunction("set_stage", SetStageFn);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user