2011-09-23 10:50:29 +00:00
// Copyright ClockworkMod, LLC. Reference and porting purposes only. Usage of the extendedcommand API
// is restricted to those granted explicit permission, or by use of the ROM Manager Recovery API.
// https://github.com/koush/TestRomManager
2010-12-20 04:37:57 +00:00
# include <ctype.h>
# include <errno.h>
# include <fcntl.h>
# include <getopt.h>
# include <limits.h>
# include <linux/input.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/reboot.h>
# include <sys/types.h>
# include <time.h>
# include <unistd.h>
# include <sys/wait.h>
# include <sys/limits.h>
# include <dirent.h>
# include <sys/stat.h>
# include <signal.h>
# include <sys/wait.h>
# include "bootloader.h"
# include "common.h"
# include "cutils/properties.h"
# include "firmware.h"
# include "install.h"
# include "minui/minui.h"
# include "minzip/DirUtil.h"
# include "roots.h"
# include "recovery_ui.h"
# include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
# include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
# include "extendedcommands.h"
# include "nandroid.h"
# include "mounts.h"
# include "flashutils/flashutils.h"
# include "edify/expr.h"
# include "mtdutils/mtdutils.h"
# include "mmcutils/mmcutils.h"
//#include "edify/parser.h"
Value * UIPrintFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
char * * args = ReadVarArgs ( state , argc , argv ) ;
if ( args = = NULL ) {
return NULL ;
}
int size = 0 ;
int i ;
for ( i = 0 ; i < argc ; + + i ) {
size + = strlen ( args [ i ] ) ;
}
char * buffer = malloc ( size + 1 ) ;
size = 0 ;
for ( i = 0 ; i < argc ; + + i ) {
strcpy ( buffer + size , args [ i ] ) ;
size + = strlen ( args [ i ] ) ;
free ( args [ i ] ) ;
}
free ( args ) ;
buffer [ size ] = ' \0 ' ;
char * line = strtok ( buffer , " \n " ) ;
while ( line ) {
ui_print ( " %s \n " , line ) ;
line = strtok ( NULL , " \n " ) ;
}
return StringValue ( buffer ) ;
}
Value * RunProgramFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
if ( argc < 1 ) {
return ErrorAbort ( state , " %s() expects at least 1 arg " , name) ;
}
char * * args = ReadVarArgs ( state , argc , argv ) ;
if ( args = = NULL ) {
return NULL ;
}
char * * args2 = malloc ( sizeof ( char * ) * ( argc + 1 ) ) ;
memcpy ( args2 , args , sizeof ( char * ) * argc ) ;
args2 [ argc ] = NULL ;
fprintf ( stderr , " about to run program [%s] with %d args \n " , args2 [ 0 ] , argc ) ;
pid_t child = fork ( ) ;
if ( child = = 0 ) {
execv ( args2 [ 0 ] , args2 ) ;
fprintf ( stderr , " run_program: execv failed: %s \n " , strerror ( errno ) ) ;
_exit ( 1 ) ;
}
int status ;
waitpid ( child , & status , 0 ) ;
if ( WIFEXITED ( status ) ) {
if ( WEXITSTATUS ( status ) ! = 0 ) {
fprintf ( stderr , " run_program: child exited with status %d \n " ,
WEXITSTATUS ( status ) ) ;
}
} else if ( WIFSIGNALED ( status ) ) {
fprintf ( stderr , " run_program: child terminated by signal %d \n " ,
WTERMSIG ( status ) ) ;
}
int i ;
for ( i = 0 ; i < argc ; + + i ) {
free ( args [ i ] ) ;
}
free ( args ) ;
free ( args2 ) ;
char buffer [ 20 ] ;
sprintf ( buffer , " %d " , status ) ;
return StringValue ( strdup ( buffer ) ) ;
}
Value * FormatFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
char * result = NULL ;
if ( argc ! = 1 ) {
return ErrorAbort ( state , " %s() expects 1 arg , got % d " , name, argc) ;
}
char * path ;
if ( ReadArgs ( state , argv , 1 , & path ) < 0 ) {
return NULL ;
}
ui_print ( " Formatting %s... \n " , path ) ;
if ( 0 ! = format_volume ( path ) ) {
free ( path ) ;
return StringValue ( strdup ( " " ) ) ;
}
2011-02-27 20:42:24 +00:00
if ( strcmp ( path , " /data " ) = = 0 & & has_datadata ( ) ) {
ui_print ( " Formatting /datadata... \n " , path ) ;
if ( 0 ! = format_volume ( " /datadata " ) ) {
free ( path ) ;
return StringValue ( strdup ( " " ) ) ;
}
2011-04-24 02:01:16 +00:00
if ( 0 ! = format_volume ( " /sdcard/.android_secure " ) ) {
free ( path ) ;
return StringValue ( strdup ( " " ) ) ;
}
2011-02-27 20:42:24 +00:00
}
2010-12-20 04:37:57 +00:00
done :
return StringValue ( strdup ( path ) ) ;
}
Value * BackupFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
char * result = NULL ;
if ( argc ! = 1 ) {
return ErrorAbort ( state , " %s() expects 1 args , got % d " , name, argc) ;
}
char * path ;
if ( ReadArgs ( state , argv , 1 , & path ) < 0 ) {
return NULL ;
}
if ( 0 ! = nandroid_backup ( path ) )
return StringValue ( strdup ( " " ) ) ;
return StringValue ( strdup ( path ) ) ;
}
Value * RestoreFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
if ( argc < 1 ) {
return ErrorAbort ( state , " %s() expects at least 1 arg " , name) ;
}
char * * args = ReadVarArgs ( state , argc , argv ) ;
if ( args = = NULL ) {
return NULL ;
}
char * * args2 = malloc ( sizeof ( char * ) * ( argc + 1 ) ) ;
memcpy ( args2 , args , sizeof ( char * ) * argc ) ;
args2 [ argc ] = NULL ;
char * path = strdup ( args2 [ 0 ] ) ;
int restoreboot = 1 ;
int restoresystem = 1 ;
int restoredata = 1 ;
int restorecache = 1 ;
int restoresdext = 1 ;
int i ;
for ( i = 1 ; i < argc ; i + + )
{
if ( args2 [ i ] = = NULL )
continue ;
if ( strcmp ( args2 [ i ] , " noboot " ) = = 0 )
restoreboot = 0 ;
else if ( strcmp ( args2 [ i ] , " nosystem " ) = = 0 )
restoresystem = 0 ;
else if ( strcmp ( args2 [ i ] , " nodata " ) = = 0 )
restoredata = 0 ;
else if ( strcmp ( args2 [ i ] , " nocache " ) = = 0 )
restorecache = 0 ;
else if ( strcmp ( args2 [ i ] , " nosd-ext " ) = = 0 )
restoresdext = 0 ;
}
for ( i = 0 ; i < argc ; + + i ) {
free ( args [ i ] ) ;
}
free ( args ) ;
free ( args2 ) ;
2010-12-30 07:36:03 +00:00
if ( 0 ! = nandroid_restore ( path , restoreboot , restoresystem , restoredata , restorecache , restoresdext , 0 ) ) {
2010-12-20 04:37:57 +00:00
free ( path ) ;
return StringValue ( strdup ( " " ) ) ;
}
return StringValue ( path ) ;
}
Value * InstallZipFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
char * result = NULL ;
if ( argc ! = 1 ) {
return ErrorAbort ( state , " %s() expects 1 args , got % d " , name, argc) ;
}
char * path ;
if ( ReadArgs ( state , argv , 1 , & path ) < 0 ) {
return NULL ;
}
if ( 0 ! = install_zip ( path ) )
return StringValue ( strdup ( " " ) ) ;
return StringValue ( strdup ( path ) ) ;
}
2011-09-06 04:14:06 +00:00
Value * MountFn ( const char * name , State * state , int argc , Expr * argv [ ] ) {
char * result = NULL ;
if ( argc ! = 1 ) {
return ErrorAbort ( state , " %s() expects 1 args , got % d " , name, argc) ;
}
char * path ;
if ( ReadArgs ( state , argv , 1 , & path ) < 0 ) {
return NULL ;
}
if ( 0 ! = ensure_path_mounted ( path ) )
return StringValue ( strdup ( " " ) ) ;
return StringValue ( strdup ( path ) ) ;
}
2010-12-20 04:37:57 +00:00
void RegisterRecoveryHooks ( ) {
2011-09-06 04:14:06 +00:00
RegisterFunction ( " mount " , MountFn ) ;
2010-12-20 04:37:57 +00:00
RegisterFunction ( " format " , FormatFn ) ;
RegisterFunction ( " ui_print " , UIPrintFn ) ;
RegisterFunction ( " run_program " , RunProgramFn ) ;
RegisterFunction ( " backup_rom " , BackupFn ) ;
RegisterFunction ( " restore_rom " , RestoreFn ) ;
RegisterFunction ( " install_zip " , InstallZipFn ) ;
}
static int hasInitializedEdify = 0 ;
int run_script_from_buffer ( char * script_data , int script_len , char * filename )
{
if ( ! hasInitializedEdify ) {
RegisterBuiltins ( ) ;
RegisterRecoveryHooks ( ) ;
FinishRegistration ( ) ;
hasInitializedEdify = 1 ;
}
Expr * root ;
int error_count = 0 ;
yy_scan_bytes ( script_data , script_len ) ;
int error = yyparse ( & root , & error_count ) ;
printf ( " parse returned %d; %d errors encountered \n " , error , error_count ) ;
if ( error = = 0 | | error_count > 0 ) {
//ExprDump(0, root, buffer);
State state ;
state . cookie = NULL ;
state . script = script_data ;
state . errmsg = NULL ;
char * result = Evaluate ( & state , root ) ;
if ( result = = NULL ) {
printf ( " result was NULL, message is: %s \n " ,
( state . errmsg = = NULL ? " (NULL) " : state . errmsg ) ) ;
free ( state . errmsg ) ;
return - 1 ;
} else {
printf ( " result is [%s] \n " , result ) ;
}
}
return 0 ;
}
2011-09-23 10:57:25 +00:00
# define EXTENDEDCOMMAND_SCRIPT " / cache / recovery / extendedcommand"
int run_and_remove_extendedcommand ( )
{
char tmp [ PATH_MAX ] ;
sprintf ( tmp , " cp %s /tmp/%s " , EXTENDEDCOMMAND_SCRIPT , basename ( EXTENDEDCOMMAND_SCRIPT ) ) ;
__system ( tmp ) ;
remove ( EXTENDEDCOMMAND_SCRIPT ) ;
int i = 0 ;
for ( i = 20 ; i > 0 ; i - - ) {
ui_print ( " Waiting for SD Card to mount (%ds) \n " , i ) ;
if ( ensure_path_mounted ( " /sdcard " ) = = 0 ) {
ui_print ( " SD Card mounted... \n " ) ;
break ;
}
sleep ( 1 ) ;
}
remove ( " /sdcard/clockworkmod/.recoverycheckpoint " ) ;
if ( i = = 0 ) {
ui_print ( " Timed out waiting for SD card... continuing anyways. " ) ;
}
ui_print ( " Verifying SD Card marker... \n " ) ;
struct stat st ;
if ( stat ( " /sdcard/clockworkmod/.salted_hash " , & st ) ! = 0 ) {
ui_print ( " SD Card marker not found... \n " ) ;
if ( volume_for_path ( " /emmc " ) ! = NULL ) {
ui_print ( " Checking Internal SD Card marker... \n " ) ;
ensure_path_unmounted ( " /sdcard " ) ;
if ( ensure_path_mounted_at_mount_point ( " /emmc " , " /sdcard " ) ! = 0 ) {
ui_print ( " Internal SD Card marker not found... continuing anyways. \n " ) ;
// unmount everything, and remount as normal
ensure_path_unmounted ( " /emmc " ) ;
ensure_path_unmounted ( " /sdcard " ) ;
ensure_path_mounted ( " /sdcard " ) ;
}
}
}
sprintf ( tmp , " /tmp/%s " , basename ( EXTENDEDCOMMAND_SCRIPT ) ) ;
int ret ;
# ifdef I_AM_KOUSH
if ( 0 ! = ( ret = before_run_script ( tmp ) ) ) {
ui_print ( " Error processing ROM Manager script. Please verify that you are performing the backup, restore, or ROM installation from ROM Manager v4.4.0.0 or higher. \n " ) ;
return ret ;
}
# endif
return run_script ( tmp ) ;
}
int extendedcommand_file_exists ( )
{
struct stat file_info ;
return 0 = = stat ( EXTENDEDCOMMAND_SCRIPT , & file_info ) ;
}
int edify_main ( int argc , char * * argv ) {
load_volume_table ( ) ;
process_volumes ( ) ;
RegisterBuiltins ( ) ;
RegisterRecoveryHooks ( ) ;
FinishRegistration ( ) ;
if ( argc ! = 2 ) {
printf ( " edify <filename> \n " ) ;
return 1 ;
}
FILE * f = fopen ( argv [ 1 ] , " r " ) ;
if ( f = = NULL ) {
printf ( " %s: %s: No such file or directory \n " , argv [ 0 ] , argv [ 1 ] ) ;
return 1 ;
}
char buffer [ 8192 ] ;
int size = fread ( buffer , 1 , 8191 , f ) ;
fclose ( f ) ;
buffer [ size ] = ' \0 ' ;
Expr * root ;
int error_count = 0 ;
yy_scan_bytes ( buffer , size ) ;
int error = yyparse ( & root , & error_count ) ;
printf ( " parse returned %d; %d errors encountered \n " , error , error_count ) ;
if ( error = = 0 | | error_count > 0 ) {
//ExprDump(0, root, buffer);
State state ;
state . cookie = NULL ;
state . script = buffer ;
state . errmsg = NULL ;
char * result = Evaluate ( & state , root ) ;
if ( result = = NULL ) {
printf ( " result was NULL, message is: %s \n " ,
( state . errmsg = = NULL ? " (NULL) " : state . errmsg ) ) ;
free ( state . errmsg ) ;
} else {
printf ( " result is [%s] \n " , result ) ;
}
}
return 0 ;
}
int run_script ( char * filename )
{
struct stat file_info ;
if ( 0 ! = stat ( filename , & file_info ) ) {
printf ( " Error executing stat on file: %s \n " , filename ) ;
return 1 ;
}
int script_len = file_info . st_size ;
char * script_data = ( char * ) malloc ( script_len + 1 ) ;
FILE * file = fopen ( filename , " rb " ) ;
fread ( script_data , script_len , 1 , file ) ;
// supposedly not necessary, but let's be safe.
script_data [ script_len ] = ' \0 ' ;
fclose ( file ) ;
LOGI ( " Running script: \n " ) ;
LOGI ( " \n %s \n " , script_data ) ;
int ret = run_script_from_buffer ( script_data , script_len , filename ) ;
free ( script_data ) ;
return ret ;
}