FORUMS
Remove All Ads from XDA

[INFO] Edify scripts in CWM recovery

816 posts
Thanks Meter: 469
 
By NFHimself, Senior Member on 26th July 2011, 10:39 PM
Post Reply Email Thread
Hi, I haven't seen any good resources for how to edit edify scripts, so I thought I would create this thread so we can pool our knowledge on the subject.
Intro

Inside your typical CWM zip there is a folder called META-INF, inside that there is a folder called com and come CERT files, inside that com folder there is a google folder, inside that is an android folder containing an update-binary file and an updater-script. If you only see an update-script, that means you are back in the Android 1.5 era and need to move on.

The updater-script

The updater-script file is a text file, it is linux formatted with regard to end of line conventions. If you use Windows then you have to edit the file using a program that keeps line feeds the way they are and has options for doing the conversion from <CR><LF> to just <LF>.

Like lisp, the contents of the text file evaluate to one big expression, but it does have the ";" end of command convention to make things more familiar, it just means perform the action on the left. (ref. google source README) You can ignore that and just treat everything as a series of commands for all practical purposes. I mention it because you need not worry about having too large a procedural block or worry about having extra spaces or worry about ending on a line boundary. You could have your entire script on one giant line and it wouldn't matter.

There are around a dozen commands, it's not terribly difficult to learn.

The updater-binary

There are a lot of updater-binary files out there in the wild, each manufacturer basically compiles there own with every other OTA update. Success in flashing your CWM zip is determined by picking the right one that works with what you are trying to do. If your knowledge says mount needs 4 arguments and the binary only supports 3, then you need to change your script to use 3 and vice versa. If you are trying to flash a radio, the updater-binary might have been recompiled to allow for that specific functionality and you will get a status 6 error when trying to flash it unless you use that update-binary. You will see the write_raw_image() function not supporting "/dev/block/mmcblk0p8" but instead "logo.bin".

However, by and large, the generic functionality is the same across the board.

Updater-script functions (In order of interest)
  • ui_print(msg1, .. msgN); This is the means you have to display something on the screen in CWM, it takes a series of comma separated arguments, each comma needs to have a space after it, this applies to all commands.

    Ex. ui_print("Your version is: ", file_getprop("/system/build.prop", "ro.build.id"));

  • show_progress(TOTALAMOUNT, TIMEINSEC); This command and the following command control what you see in the progress bar at the bottom. It is not necessary to use it, it's just another way to display information.TIMEINSEC refers to how long it will take for the progress bar to move to the AMOUNT specified. You would use this perhaps when something is taking a long time, you know approximately how long and want the screen to keep showing something while it is going on. If you use zero for TIME then nothing is done, you have just set the maximum amount for use with set_progress. The amount is a decimal number, 0.5 would be half the progress bar being filled.

    Ex. show_progress("0.300000", 10);

  • set_progress(AMOUNT); This command sets the pointer or fill amount of the progress bar according to the last show_progress command. It should never be greater than the total of the show_progress amount.

    Ex. show_progress("0.300000", 0);
    set_progress("0.15");
  • mount(TYPE, DEV, PATH); This is one version of the mount command. The TYPE arg is usually "MTD", which refers to memory technology device. The DEV for a MTD would be something like "system", "userdata", "cache", and the PATH would be "/system", "/data", or "/cache". You will also see TYPE be "vfat".

  • mount(FSTYPE, TYPE, DEV, PATH); This seems to be the more current mount command. It adds in the file system type. Ex. "ext3", "yaffs". TYPE with this command can be "MTD" or "EMMC". You would use "EMMC" with "/dev/block/mmcblk0p8".

  • umount(PATH); This simply removes a previous mounted PATH from the system. Ex. umount("/system"); You'll notice the double quotes around command arguments, they are not strictly necessary. Unless it's a reserved word (if then else endif) then they can be anything. "consisting of only letters, numbers, colons, underscores, slashes, and periods". So if you just spend 10 minutes uploading your zip to your phone and notice that your unmount command is umount(/system);, it will work just fine.
  • sleep(SECS); Simply pauses for SECS seconds.

  • package_extract_file(FILE, FILEWITHPATH); This command extracts one of your files from the CWM zip package and save it to the phone.

    Ex. package_extract_file("bootanimation.zip", "/system/media/bootanimation.zip");
  • package_extract_dir(ZIPPATH, PATH); This command extracts an entire folder in your CWM zip to a folder on your phone.

    Ex. package_extract_dir("system", "/system"); *This is where having system mounted would be handy, without it being mounted, the files would be copied to the ramdisk /system.

  • write_raw_image(PATH, PARTITION); This is one of those tricky ones, the PATH is somewhere on your phone with the image to be flashed to a PARTITION on your phone. The trouble is, how do you specify what partition gets flashed? Is there any restriction on where the file has to be? If MTD conventions are used, you are looking for "system", "boot", "recovery", "logo.bin". (All this means that each partition has a name stored somewhere, and if you know it, you can write to it.) Maybe it will accept device references like /dev/block/mmcblk0p8. This depends on the update-binary file you are using.

    Ex. write_raw_image("/tmp/logo.bin", "logo.bin");
    Ex. write_raw_image("/tmp/logo.bin", "/dev/block/mmcblk0p8");

  • write_firmware_image(PATH, PARTITION); You would think it would be the same as write_raw_image. Not sure what the difference is.


  • run_program(PROG, ARG1, .., ARGN); Pretty self explanatory, This command allows you to execute a program or script on the phone. Instead of all the bits of the command being separated by spaces, commas are used. It returns an error code as a string.

    Ex. run_command("ls", "-R", "/system");
  • Assert(condition); You'll see this one a lot in OTA updates, all it does is abort the script if something goes wrong. If condition is false, the script ends displaying a description on the phone of what command caused the exit. You can put in more than one statement here, separated by ";", if any one of them returns with an error, the script exits.

    Ex. Assert(mount("ext3", "EMCC", "/dev/block/mmcblk0p12", "/system")); *If you can't mount /system and your CWM zip only writes to system, you might as well stop it before continuing on to write to the ramdisk.

  • ifelse(condition, true path, false path); This is your basic conditional statement, the tricky bit is to figure out what statements in edify can trigger a true of false condition. As for the rest of it, the commas separate the two blocks.

    Ex. ifelse(file_getprop("/system/default.prop", "ro.build.id") == "OLYFR1.2.3.4", ui_print("yes"), ui_print("false"));

  • abort(); This stops the script, useful with ifelse.
  • file_getprop(PATH, VALUE); This command looks for a text file containing A=B pairs and returns B if it can find an A.

    Ex. file bob.txt exists in /tmp, it contains cool=yes, and dorky=true123 each on separate lines.

    file_getprop("/tmp/bob.txt", "cool") == "yes"
    file_getprop("/tmp/bob.txt", "dorky") == "true123"

  • getprop(VALUE); Functions the same as file_getprop, without the file part. It looks through the system value pairs for a matching value.

    Ex. getprop("ro.build.id") == "OLYEM1.2.3.4"
  • delete(PATH1, ...,PATHN); Nothing to see here, just a delete command, full path to the file(s) as argument(s).

  • delete_recursive(PATH1, ...,PATHN); It's a delete everything in a folder, including subfolders command. The folder itself is deleted as well.

  • set_perm(UID, GID, MODE, PATH1, ..., PATHN); Set the linux permissions on a file, ownership and flags at the same time. Equivalent to chown and chmod in the one command.

    Ex. set_perm(0, 0, 06755, /system/bin/su, /system/bin/shsu); *0 stands for root, so it would be owned by root, of the group root, with suid bit set and standard executable bits set.

  • set_perm_recursive(UID, GID, DIRMODE, FILEMODE, PATH1, ...,PATHN); Same as above except with folders instead of files. Use the DIRMODE to set the permissions and ownership of the folders themselves, and FILEMODE to set the permissions of the files within them.

  • symlink(TARGET, LINK1, ...,LINKN); It's the equivalent to the linux ln -s command. For our purposes, it might as well be called busybox install.

    Ex. symlink("/system/bin/busybox", "/system/bin/awk", "/system/bin/wget", "/system/bin/sed");




To Be Continued..

References

http://devphone.org/development/edif...tax-explained/
http://www.synfulgeek.com/main/index...el-source-code
https://github.com/koush/android_boo...r/edify/README
http://tjworld.net/wiki/Android/Upda...EdifyFunctions
The Following 42 Users Say Thank You to NFHimself For This Useful Post: [ View ] Gift NFHimself Ad-Free
 
 
27th July 2011, 07:34 PM |#2  
NFHimself's Avatar
OP Senior Member
Flag Mount Pearl
Thanks Meter: 469
 
Donate to Me
More
Tips:

You can use the abort() command to step through your updater script, for instance if you wanted to check various combinations on syntax for write_raw_image();

In /tmp there is a text file called recovery.log, do a cat /tmp/recovery.log to see extra output of your script from failed commands.
The Following User Says Thank You to NFHimself For This Useful Post: [ View ] Gift NFHimself Ad-Free
28th July 2011, 08:35 PM |#3  
briggie108's Avatar
Member
Flag Portland, ME
Thanks Meter: 10
 
More
Quote:
Originally Posted by NFHimself

The updater-script file is a text file, it is linux formatted with regard to end of line conventions. If you use Windows then you have to edit the file using a program that keeps line feeds the way they are and has options for doing the conversion from <CR><LF> to just <LF>.

If you are in windows, I have found that notepad++ does the job just fine.
http://notepad-plus-plus.org/
The Following 2 Users Say Thank You to briggie108 For This Useful Post: [ View ] Gift briggie108 Ad-Free
28th March 2014, 06:17 PM |#4  
what about the FORMAT command?
actually i have error on a CM installation, its says

Code:
format() expects 3 args, got 2.
but my format command have 3 args:
Code:
format("ext4", "/dev/block/mmcblk0p10", "/system");
23rd June 2014, 03:57 PM |#5  
kevp75's Avatar
Recognized Contributor
Flag MA
Thanks Meter: 6,872
 
Donate to Me
More
Thumbs up
Quote:
Originally Posted by NFHimself

Hi, I haven't seen any good resources for how to edit edify scripts, so I thought I would create this thread so we can pool our knowledge on the subject.
[INDENT][INDENT]Intro

Thanks for this... but I do have a question....

I am attempting to see if busybox is installed on a device, and if not install it, or proceed

so, so far I have:

Code:
ifelse(
	BUSYBOX DOESNT EXIST,
	(
		ui_print("* Did not find it. Installing...");
		set_perm(0, 1000, 0755, "/system/xbin/busybox");
		symlink("/system/xbin/busybox", "/system/bin/busybox");
		run_program("/system/xbin/busybox", "--install", "-s", "/system/xbin");
	),
	(
		ui_print("* Found it. Proceeding...");
	)
);
You can see where I'm lost I was thinking of using assert to run_program("/system/xbin/busybox", "vi", "/system/xbin"); just as a simple check... but from what I can see, if the assertion fails it will stop the script, and print out the failure message, which of course is not what I am after here... or maybe I am, can it be used to do a check rather than stop the script?
23rd June 2014, 04:38 PM |#6  
ravilov's Avatar
Senior Member
Thanks Meter: 1,349
 
Donate to Me
More
Just an idea (ie. untested):
Code:
ifelse(
    run_program("/system/bin/sh", "-c", "test -e /system/xbin/busybox")
    ...
)
The Following User Says Thank You to ravilov For This Useful Post: [ View ] Gift ravilov Ad-Free
23rd June 2014, 04:43 PM |#7  
kevp75's Avatar
Recognized Contributor
Flag MA
Thanks Meter: 6,872
 
Donate to Me
More
Quote:
Originally Posted by ravilov

Just an idea (ie. untested):

Code:
ifelse(
    run_program("/system/bin/sh", "-c", "test -e /system/xbin/busybox")
    ...
)

trying to run that in adb sheel, and don't get a response, but it does seem like a good idea... I assume Edify would return a 1/0 or true/false string from it, and I can just check for that?

EDIT: Maybe I do get something back... after running that in adb shell my next line looks like the following:
Code:
1|root@jflte:/ #
Am I right in assuming that "1" is the output?
23rd June 2014, 04:51 PM |#8  
ravilov's Avatar
Senior Member
Thanks Meter: 1,349
 
Donate to Me
More
Yes. The command won't ever return any output, it only returns the exit status. Your shell is obviously set so it includes a non-zero exit status in the prompt. (Non-zero traditionally means error.)
The Following User Says Thank You to ravilov For This Useful Post: [ View ] Gift ravilov Ad-Free
23rd June 2014, 05:14 PM |#9  
kevp75's Avatar
Recognized Contributor
Flag MA
Thanks Meter: 6,872
 
Donate to Me
More
Quote:
Originally Posted by ravilov

Yes. The command won't ever return any output, it only returns the exit status. Your shell is obviously set so it includes a non-zero exit status in the prompt. (Non-zero traditionally means error.)

that prompt means that the test failed, and I don't have busybox installed?

I'm just a tad confused... (this is my first full-on edify script), and I do have busybox installed

I appreciate the help, and once I get my tapatalk working right on my phone, I'll give ya all the "thanks" for the help with this

Eh... everything I 'test' returns the same thing
Code:
1|root@jflte:/ #
23rd June 2014, 06:20 PM |#10  
ravilov's Avatar
Senior Member
Thanks Meter: 1,349
 
Donate to Me
More
Hm, weird. It works for me...
Code:
# /system/bin/sh -c 'test -e /system/xbin/busybox'; echo $?
0   <-- no error - file exists
# /system/bin/sh -c 'test -e /system/xbin/busybox1'; echo $?
1   <-- error - file does not exist
I didn't try it in an edify script because I don't feel like rebooting my phone right now, but I don't see why it wouldn't work.
Try running the "sh -c test ..." command in adb shell while in recovery and see what happens.

Also, just a side note: backslash is NOT the same as slash. If you are going to write shell/edify scripts, you need to know at least that distinction. That is why your [code] tags are not working right.
The Following User Says Thank You to ravilov For This Useful Post: [ View ] Gift ravilov Ad-Free
23rd June 2014, 06:54 PM |#11  
kevp75's Avatar
Recognized Contributor
Flag MA
Thanks Meter: 6,872
 
Donate to Me
More
Quote:
Originally Posted by ravilov

Hm, weird. It works for me...

Code:
# /system/bin/sh -c 'test -e /system/xbin/busybox'; echo $?
0   <-- no error - file exists
# /system/bin/sh -c 'test -e /system/xbin/busybox1'; echo $?
1   <-- error - file does not exist
I didn't try it in an edify script because I don't feel like rebooting my phone right now, but I don't see why it wouldn't work.
Try running the "sh -c test ..." command in adb shell while in recovery and see what happens.

Also, just a side note: backslash is NOT the same as slash. If you are going to write shell/edify scripts, you need to know at least that distinction. That is why your [code] tags are not working right.

I see, I wasn't doing the echo, and what you posted shows exactly what you posted. DOH on the CODE

So I have it on record (for my own personal reference)
Code:
ifelse(
	((run_program("/system/bin/sh", "-c", "test -e /system/xbin/busybox; echo $?") == 1 ||
	(run_program("/system/bin/sh", "-c", "test -e /system/bin/busybox; echo $?") == 1 ||
	(run_program("/system/bin/sh", "-c", "test -e /system/xbin/busibox; echo $?") == 1 ||
	(run_program("/system/bin/sh", "-c", "test -e /system/bin/busibox; echo $?") == 1),
	(
		ui_print("* Did not find it. Installing...");
		set_perm(0, 1000, 0755, "/system/xbin/busybox");
		symlink("/system/xbin/busybox", "/system/bin/busybox");
		run_program("/system/xbin/busybox", "--install", "-s", "/system/xbin");
	),
	(
		ui_print("* Found it. Proceeding...");
	)
);
and yes, I meant the 'busibox' part, because I have seen that in some roms
Post Reply Subscribe to Thread

Guest Quick Reply (no urls or BBcode)
Message:
Previous Thread Next Thread
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes