624 Commits
eclair ... ics

Author SHA1 Message Date
1e2da51172 Merge branch 'ics' of github.com:CyanogenMod/android_bootable_recovery into ics 2012-06-07 11:58:13 +01:00
8ba9a6335b Fix build on gcc 4.6.
Several programs were not linked against libcrecovery which has the __system
function.

Change-Id: I12b33a9157ab74825129896d0f2177fa83638464
Signed-off-by: Evan McClain <aeroevan@gmail.com>
2012-05-18 01:28:26 -04:00
9a7615326e use TARGET_RECOVERY_FSTAB location if defined
If TARGET_RECOVERY_FSTAB is defined use this location to find
recovery.fstab

Change-Id: Ic4cd26f5be064586359f39ff82d7f9b09ce57f53
2012-05-06 11:14:41 +02:00
08bedb21d8 remove copyright, switch to AOSP license
Change-Id: I53485386d68726f5c0596ac842e6a480d4463b74
2012-04-10 13:23:50 -07:00
7ba8a30150 Merge pull request #21 from IEF/ics
Fix BCB clearing for eMMC devices.
2012-04-09 09:34:19 -07:00
IEF
21b8a12300 Always call set_bootloader_message(), not just for MTD-devices. set_bootloader_message has a built-in check for MTD/eMMC via fstab. 2012-03-07 16:50:26 +01:00
d87b8df56d Remove random offset message during installation
Change-Id: I2281a571e37ba9fac2b99806ce9c63e591b4d39f
2012-02-13 16:18:53 -05:00
1c50ff29e6 Fix ui menu bug for long menus.
Change-Id: If009dee6b7597daeec62dd65baa7ad35e1adec5d

Conflicts:

	ui.c
2012-01-31 20:28:36 -08:00
a465962667 use source built e2fsprogs! thanks cvpcs!
Change-Id: Id3067d4da53643ae1af0b9f15445262afda7b197
2012-01-30 22:51:36 -08:00
e2a66586a3 fix up key value parsing
Change-Id: I05e821cd1215c44be780694644e568676fd67565
2012-01-29 14:03:04 -08:00
10034aabc9 Merge "Always run adbd as root in recovery." into ics 2012-01-28 09:26:53 +03:00
638103922f more derpage
Change-Id: I878386195a408d2a98137816515f5eaaa52ccf79
2012-01-27 02:58:40 -08:00
67e73e1559 fix build
Change-Id: Iac099f5a275b9633ed30d9e4a84acb99a57c4434
2012-01-27 02:46:19 -08:00
3cdfd138fa Various fixes to fix rendering of text. There will always be 3 lines of log shown. The menu can have long items in it now, rather than being truncated. The log text will be bottom aligned.
Change-Id: I09289e053c8ab673814318da55302efaab0404de

derp

Change-Id: I3fc31f5ea311c73c0ec999aa77d3fa0d01238001
2012-01-26 22:56:33 -08:00
ccc1fdb386 derp
Change-Id: I5ffece3af80c0c328c61975d46f4de4cb22f2282
2012-01-26 16:49:58 -08:00
18e3f62ad2 Fix up the mess around fonts and defines.
Change-Id: I3df3dae482ac6f8e9ddcbe2946dba43428bf46b1
2012-01-26 16:49:33 -08:00
b20a4812ba reversed the logic
Change-Id: I62c104ee0c9218f929c10eda31f4bf5828b0de22
2012-01-26 15:29:08 -08:00
5617056cb8 Recovery : Show menu if in non user initiated mode and error occurred
When using rom manager and applying a zip, if one encounters an error in recovery,
they're left on a screen with no visible controls (Forcing to hard reset phone).

Change-Id: Ia9b2f396fc95c7972a5a5580e1a50adf4af26060
2012-01-26 15:20:57 -08:00
aa3c3d429b Respect volume length when formatting ext4 when restoring
This is needed for device encryption to work properly (there must
be space for a 16 KB footer at the end of the partition, which is
usually specified by the length option).

And yes, the old signature of make_ext4fs was wrong, but worked
anyway because the related header was not included and the compiler
let it pass an as implicit delcaration.

Change-Id: Ied7ec70bebc120cc2917771f59eeaeb7ea76bf8d
2012-01-26 15:16:53 -08:00
cd3705e4ab remove power off. not useful in the main menu.
Change-Id: I8923d1e878994c3516798118961b4cdaa82ddc88
2012-01-26 15:09:08 -08:00
4f78176329 Misc tweaks / bug fixes
- readd "power off" to the main menu
- fix bug where stdout overflows into menu text
- remove +++++Go Back+++++ from main menu as there is nothing to go back to (detects menu depth)

Change-Id: Icb84ac86e55712412d07add0ab76955d7902f07c
2012-01-26 15:08:15 -08:00
de338e56b3 Big Font Mod and Roboto Fonts (XHDPI, HDPI, and MDPI)
- lets xhdpi devices (Galaxy Nexus, Xoom, etc) have a bigger font size (15x24)
- port Google's Roboto font into recovery for both XHDPI, HDPI, and MDPI font size, make them optional (LDPI is too small!)

(credits to gweedo767 for big font)

Change-Id: I621dbc7c8ac30a8f16039ce64720512e3e63881a
2012-01-26 14:57:07 -08:00
5a44ceb692 remove hacky board define around usb storage mounting on /data/media devices.
Change-Id: I2d382762271a2cfc6d83454160ed127b7457c88c
2012-01-26 14:56:56 -08:00
4c8e2482a6 Who approves this stuff... use get_volume_for_path('/sdcard') and check for null...
Revert "Hide "mount USB storage" option from mount menu when the board has a virtual sdcard"

This reverts commit e510810c71.
2012-01-26 14:47:34 -08:00
059db9bfb6 Always run adbd as root in recovery.
At present, invoking "adb shell" while in recovery results in:

- exec '/system/bin/sh' failed: No such file or directory (2) -

"adb shell" should invoke /sbin/sh, but cannot as /sbin and /sbin/recovery
lack other-user execute permission.  Invoking "adb root" to restart adbd as
root _does_ work, however this behavior may not be intuitive to users who
encounter the above error.

The solution implemented here is to always run adbd as root in recovery, so
it has permission to run /sbin/sh.  Furthemore, user shells in recovery are
not particularly useful and "su" doesn't exist, thus "adb root" is likely
to be invoked anyways.

Change-Id: Iaaa25090e85d970e9a076fef068f5fae8202ab0b
2012-01-26 16:05:56 -05:00
e510810c71 Hide "mount USB storage" option from mount menu when the board has a virtual sdcard
Change-Id: I4e59768e9f34f0fb33d88ad382feaa2515d70bc4
2012-01-15 02:37:34 -05:00
4e50004a0e fix yes/no issue where the index is 0 and not 7 2012-01-13 14:16:03 +00:00
d43f5a01bf merge, and fix extendedcommands.c for yes/no 2012-01-11 11:10:07 +00:00
1cb1ce343b fix yes/no 2012-01-11 11:08:31 +00:00
9487d2965f add comments around /data/media
Change-Id: I35ad822ed602e2b1018f1e1a0d67499867b60a40
2011-12-18 13:49:52 -08:00
d4c04cb00b Merge branch 'ics' of git://github.com/CyanogenMod/android_bootable_recovery into ics 2011-12-18 13:40:30 -08:00
e9039792c9 5.5.04
Change-Id: Idb2f70a8a02d2f9418356f011c9392f8d9b1d1d2
2011-12-18 11:53:08 -08:00
f0c389ddcd nandroid/root/extendedcommands: attenuate for /data not being auto in fstab
Change-Id: I0e7bec03bb29f1ae72f23321f89cf704e54ff4d9
2011-12-18 02:52:30 -05:00
357a2f5109 extendedcommands/nandroid: remove internal options if no sdcard and is_data_media
-force /data as backup_path if volume for /sdcard is null and the same is true

Change-Id: I927b723cde5b519d81402c6d841f2424627253e8

Conflicts:

	nandroid.c
2011-12-18 02:52:21 -05:00
db524c28b4 Merge "Fix wipe from android settings for devices with /datadata" into ics 2011-11-30 08:14:02 +03:00
a64c697333 Fix up the autoinclusion rules for the recoveryimage target. 2011-11-27 14:07:29 -08:00
1659814576 Fix wipe from android settings for devices with /datadata
Change-Id: I2d80d580bc2ccdc756f411dbe514270d5c245816
2011-11-26 22:44:29 +07:00
a9017dabc5 remove redundant fix 2011-11-23 14:07:06 -08:00
ddc1241a36 fix missing prebuilts in recovery. mmc bootloader message support. fix segfault happening due to C structs not being zeroed out. 2011-11-23 14:06:26 -08:00
edae7a5b0f Merge "recovery: fix non-MTD mounting (uninitialized variables)" into ics 2011-11-22 21:45:36 +03:00
d2eecca360 Update extendedcommands.c one "No". 2011-11-21 14:37:29 -08:00
b062713ee0 Merge pull request #13 from chris41g/gingerbread
Update extendedcommands.c one "No".
2011-11-21 14:37:00 -08:00
d280f6e0d8 rewrite mtd_restore_raw_partition to use the new aosp code 2011-11-21 11:22:04 -08:00
b0a63d857f Update extendedcommands.c one "No". 2011-11-20 15:26:53 -06:00
ff316eb739 recovery: fix non-MTD mounting (uninitialized variables)
Mounting failed due to invalid (garbage) fs_options
2011-11-19 13:31:21 +07:00
21ad8d04dd remove dedupe 2011-11-16 18:28:20 -08:00
0e7d88613a Support custom graphics.c. Set the recovery timeout to 1 hour. 2011-11-16 16:47:53 -08:00
0df56f4db4 wip 2011-11-16 16:00:35 -08:00
070dafc6fe fix flashing, which was breaking 2011-11-16 23:48:50 +00:00
63fb0eedbd Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-11-12 01:30:08 +00:00
88a233d5fa Fix up bmlutils to include fat.format automatically if rfs is found in the recovery.fstab. Use __system rather than run_exec_process.
Change-Id: I669bfb75cf0cc00364b815b54130c01786866406
2011-11-11 00:41:57 -08:00
2291705c41 Merge pull request #12 from DRockstar/gingerbread
Add RFS format support
2011-11-11 00:27:25 -08:00
7ef88155e0 fix advanced restore
Change-Id: I0805799343800912f8ea2caf9d06be4d59e9f4bf
2011-11-11 00:26:32 -08:00
a8f265dd6f Add RFS format support
Change-Id: Ifd1e5ce9875c3eaacc1cec1759b67e672894e279
2011-11-10 15:54:14 -06:00
e0bbe565af Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-30 19:32:02 +00:00
890b951a3d fix flash image for explicit bml path
Change-Id: Ifeccfb65d6a927440249f7ab2fd9b0512ccc491c
2011-10-29 21:38:53 -07:00
c971f76e45 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-30 02:30:05 +00:00
c9ea117b56 actually implement internal sdcard restore
Change-Id: I10799352768a2babb46dc9b74671fd3b1049583d
2011-10-29 18:48:18 -07:00
b4812b5b34 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-29 01:30:07 +01:00
4fcd523ded fix driver looking for recovery, rather than checking the basename. fix badness in nandroid menu generation.
Change-Id: I7d7011e36583509f07534e4bc85ed8d567022d3e
2011-10-28 11:47:02 -07:00
7691202e89 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-28 01:30:05 +01:00
89ed0b7355 support backup and restore on internal sdcard
Change-Id: I6295b5bb7ada967ca223758be58d555c1a2ff462
2011-10-26 21:25:34 -07:00
46ba04b01b Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-25 01:30:07 +01:00
f0e81c4643 deprecate BOARD_USES_RECOVERY_CHARGEMODE
Change-Id: Iac0a457335220d905f478b6941990adb185ba426
2011-10-23 20:17:59 -07:00
24ba583ec2 deprecate BOARD_USES_RECOVERY_CHARGEMODE
Change-Id: Ibda5585257f4380abccd97036eae3e747779a9e9
2011-10-23 20:17:49 -07:00
85850a553b Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-24 01:30:32 +01:00
6cf153cd50 Revert "zero the partiiton before writing to it."
This reverts commit 17fd32d0a2.
2011-10-23 13:28:53 -07:00
04fae9d67e fix the disabled states in init.htc.rc....
Change-Id: I475f470bc9d638383f0fd69ba0c43fe7c7928179
2011-10-23 13:20:50 -07:00
17fd32d0a2 zero the partiiton before writing to it.
Change-Id: I4717fd45c822a2026f907914c900cf8c60d8a48d
2011-10-22 22:34:58 -07:00
441031dadc minui: add ability to synchronize current key state
If a key is down prior to the time of initialization, we would not get the
down event for the key, and thus think that the key is not pressed.

Add an interface that allows one to provide a callback to execute
on all keys that are currently down.

Change-Id: I2a4096c0cb4c7c7a9a80d207835f168a0b418413
Signed-off-by: Dima Zavin <dima@android.com>
2011-10-12 15:53:32 -07:00
9996a5cd15 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-10-05 01:30:05 +01:00
2e85422f89 juggle around some of the ext handling tools. add setprop link
Change-Id: Ic091d682d42d14d4942e481a6099e04bb8d7ac21
2011-10-04 16:33:30 -07:00
f908e5bdbe Merge pull request #11 from DRockstar/gingerbread
edited nandroid.c to include rfs in fs lists, required for tar restore with rfs file systems
2011-10-04 16:32:14 -07:00
a87bb5f57b edited nandroid.c to include rfs in fs lists
Change-Id: I403331df04d6a4cf75fd898af42dec7aab5a1b59
2011-09-29 15:37:19 -05:00
f6abd409bb fix problem where the screen is sometimes all black in recovery
Change-Id: Ifa0b59e43eaf0bea9435aa4d96c5b0fc4f10fbfe
2011-09-27 13:09:48 -07:00
b1c19c1334 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-09-23 15:00:24 +01:00
95fb821c19 shuffle some code
Change-Id: Ifb5afe8ef6de7b6de58dfc07a30c1f89b5c1eb08
2011-09-23 03:57:25 -07:00
0917a7aedf note usage of extendedcommand;
Change-Id: Iab212b3a0cc5259630883c4783a28bcecd9e7028
2011-09-23 03:50:29 -07:00
3681b91861 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-09-23 01:30:31 +01:00
81a61516c9 fix text
Change-Id: I56e682be485d1bb8191f54b5df1fc2634b6d9ad5
2011-09-22 15:10:20 -07:00
fdfb636336 update recovery with new 3D images
Change-Id: I6d52fd1db27fdf1b61f41f598a2209b70385b106
2011-09-20 14:16:46 -07:00
7f13e150cf more cwr5 work.
Change-Id: I72bb14ef25a9067ccde3e40ea989c7990512687a
2011-09-08 16:55:35 -07:00
30a937a954 cwr 5
Change-Id: I70cbb4df78b0bbc9d227d19aa6d9434eba2b540d
2011-09-05 21:14:06 -07:00
88e0899617 minui: events: only open input devices with EV_KEY and/or EV_REL
Change-Id: I8283d7aaa0f66d488f462cd108350cc49657a745
Signed-off-by: Dima Zavin <dima@android.com>
2011-09-02 14:55:20 -07:00
365836736c minui: events: add ability to poll on non-input fds
Change-Id: Iad52a6f2adcae0068d252d6163586f9d7b93121d
Signed-off-by: Dima Zavin <dima@android.com>
2011-09-02 14:55:20 -07:00
bc29063bf4 minui: events: refactor event acquisition
Events are now delivered through a callback mechanism during
a call to ev_dispatch(). This will allow us to extend the events
code to handle other devices/fds, not just input. One such example
is the ability to process uevents.

During initialization, we provide an input callback to ev_init
that gets called when a new event is encountered during dispatch.

ev_get has been removed and replaced with ev_get_input() helper
function that can be called from inside the callback to attempt
to get an input event.

The existing client of ev_get in recovery has been split up such
that the input thread just calls ev_wait(); ev_dispatch(); and
the input_callback handles individual events by using the
ev_get_input() helper.

Change-Id: I24d8e71bd1533876b4ab1ae751ba200fea43c049
Signed-off-by: Dima Zavin <dima@android.com>
2011-09-02 14:55:20 -07:00
cf2de074f6 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-09-02 01:30:05 +01:00
bf5a60a034 add some error logging to mmcutils
Change-Id: I4c886822e7d47a0b5636bfc656039b171303d4e5
2011-08-31 23:28:21 -07:00
5268131918 allow explicitly provided mount locations
Change-Id: I3930b2abeb81c09c25c1750f0545c233c0d5a4a2
2011-08-31 23:26:45 -07:00
d6bf694ff0 allow overriding mke2fs and htcbatt
Change-Id: Ibff628238c39661874e1e55bfcf6d51516b6bdd5
2011-08-31 23:25:23 -07:00
4daf48a10b minui: graphics: add interface for framebuffer blank/unblank
Change-Id: I5c3ee61cbf6fadae50f10b9f2e73caceaa5048a7
Signed-off-by: Dima Zavin <dima@android.com>
2011-08-30 11:59:20 -07:00
3c7f00ede6 minui: graphics: add ability to query font size
Change-Id: I5e8f477b7b205794f2975f12e6b6010c177f6052
Signed-off-by: Dima Zavin <dima@android.com>
2011-08-30 11:58:24 -07:00
c2ddaea83a change recovery images to match blue holo theme
Change-Id: I912d3ab32973c5c5e7b6b1749698f8a71d884fa3
2011-08-19 16:56:31 -07:00
7f33591677 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-08-18 01:30:08 +01:00
01ba8bc552 updated mke2fs from motorola that should also work on non-neon devices.
Change-Id: If66906147da2a3d84745dc1e58a180dec0d1d156
2011-08-17 16:44:22 -07:00
337dcdd011 ver
Change-Id: Id02cd499546b72ab0eeb545a4479e1ba977b13cf
2011-08-15 20:33:56 -07:00
b3122e51a0 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-08-15 01:30:08 +01:00
6afbcdc651 handle mounts in recovery if the have only one argument
controlled by BOARD_RECOVERY_HANDLES_MOUNT if it is not set
the recovery will behave like before.

this allows the recovery to handle commands like 'mount system'
it is needed for devices with two different filesystem in
recovery.fstab like RFS and EXT4 cause the regular recovery
behaviour will only generate a fstab for mounts of fstype2
and ignore the other fstype. This will also enable things like

run_program("/sbin/busybox", "mount", "/system");

on those system.

Change-Id: Ib10ffc7735a2edb8dd32be230ba885d5d2744f73
2011-08-13 13:19:39 +02:00
97c7df2f33 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-08-04 01:30:08 +01:00
5e922a4bf4 Merge "adding text output for battery stats wipe. just a confirmation that it completed successfully" into gingerbread 2011-08-04 04:23:04 +04:00
5ee0380c67 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-29 01:30:08 +01:00
04a211f372 Merge "htc offmode charge: update daemons and init.htc.rc. remove png files needed by old offmode charge. add htcbatt daemon" into gingerbread 2011-07-29 03:13:34 +04:00
7b2697f66f Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-27 01:30:08 +01:00
0d651b1b70 Merge branch 'gingerbread' of git://android.git.kernel.org/platform/bootable/recovery into upstream-2.3.5 2011-07-26 13:06:34 -04:00
d41c2c8e89 htc offmode charge: update daemons and init.htc.rc. remove png files needed by old offmode charge. add htcbatt daemon
Change-Id: Id9a521decaa381b5d4cffca3fd51814a07f027ca
2011-07-24 11:37:47 -04:00
1a873797f7 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-22 01:30:08 +01:00
7e70b6be7f Deleted check for equality in flash image header and partition
header.

Skipping flash after just checking a 1K header is
incorrect in the case where something scribbles over
the partition after the header because flash_image
would not be able to rewrite the whole
partition due to this check.

Also, Samsung devices use a combined boot and
recovery image where the header is the same even if the
initramfs changes and these do not get flashed even
if the boot.img is actually different due to different
appended initramfs.

Change-Id: I53ab0a23347cdf1fa7ff58dff37e812fd84645be
2011-07-21 18:41:49 -04:00
45df699a5e cwm: Clarify on-screen labeling of recoveries
Koush is the only authoritative source for clockworkmod recoveries,
so lets try to reduce confusion as to what is "officially supported"
and what isn't...

Change-Id: Icb0f93530e69829ce69f2500b6f29df350099273
2011-07-21 16:31:57 +01:00
81a1ffea20 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-20 22:52:04 +01:00
c915937ebd herp
Change-Id: I4aace74f1d3638241939f842a4526f9724cf5dac
2011-07-20 01:26:02 -07:00
137c9f41c4 fix crash
Change-Id: I65be72b5cd8c0679fb328a78eb4016e2c89ec9b0
2011-07-20 01:19:44 -07:00
d07ffd72cd Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-20 01:30:07 +01:00
eb557e4233 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-19 01:30:06 +01:00
55e6e7dc4f graphics.c: revert RGB8888 support
Change-Id: Id2a4c8055c2bc82120871293235cf98c7c5b50e6
2011-07-18 16:42:57 -07:00
0bf56815b7 graphics.c
Change-Id: I5d9b5508a568b2ce47123524a5978628c013a1e8
2011-07-17 20:38:32 -07:00
d5d1fcdc96 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-15 01:30:07 +01:00
6242a8bc9b Support multiple recovery updater extensions.
Change-Id: I787c086223b674050c0a12fc575add9badb471af
2011-07-14 15:12:20 -07:00
cd264e7f94 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-14 01:30:07 +01:00
8918673cf7 Merge "Check pointer for null before dereferencing" 2011-07-13 15:42:09 -07:00
b2ceb696d0 Check pointer for null before dereferencing
Change-Id: Ie7563bf8fb2d627454010de7388d0992e2accf91
2011-07-13 15:24:38 -07:00
5c69bdd735 graphics: use gr_flip_32() only if we're really on a 32bpp device.
Change-Id: I996b2dadf43477064480a47ee536e6ec395a6aad
2011-07-13 12:19:47 -07:00
94a4babac7 Google Music stores their music cache /sdcard/Android...
Can't back this up unless we start selectively excluding apps, which is gross.

Most apps only store interstitial files here, so it is not a huge deal.
Apps need to be able to work properly without an SD card. (Oops ROM Manager).

Revert "backup and restore of /sdcard/Android (see getExternalFilesDir)"

This reverts commit 50732e3c67.

Conflicts:

	Android.mk

Change-Id: I3978c5521b4f29c4d709c3bb6a8fa7e53678a79e
2011-07-13 10:34:23 -07:00
e87f9e695e support explicitly provided device paths
Change-Id: I1ddb862f62932d2e1525d8b317613bf67a64093e
2011-07-12 18:07:45 -07:00
6057bade5c Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-13 01:30:07 +01:00
eb3aa6ff32 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-12 16:15:06 -07:00
1115c8f325 use sha256 instead
Change-Id: Ie4e7bfec568c786f58367f55fee866b6aae9732b
2011-07-12 16:15:05 -07:00
8d92ae052e Merge "Update usb_connected() to support new gadget driver" 2011-07-12 15:39:11 -07:00
70f25bead8 dedupe: include external/openssl/include for host build
Change-Id: I65907c5fa5736c0587567b0d6b4cfb2ce155472e
2011-07-12 14:49:39 -07:00
32ac1666e2 size
Change-Id: I0b43832bc896864abb0a659fc3bf58793879a2e8
2011-07-12 14:03:03 -07:00
7e6067e36c Update usb_connected() to support new gadget driver
Change-Id: Iabe8be5bbfa7d2bf1d13280c8734ff75b62a152f
2011-07-12 12:38:46 -07:00
b0462e6ae2 Remove the simulator target from all makefiles.
Bug: 5010576

Change-Id: Ib465fdb42c8621899bea15c04a427d7ab1641a8c
2011-07-11 22:11:45 -07:00
491f4847f6 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-12 01:30:05 +01:00
80cd7707c0 unnecessary, but clean up the open files properly.
Change-Id: I58f571fd00f914cba1102dd89d50dc08d917b671
2011-07-11 14:41:44 -07:00
24c802b05e fix up symlinks and lack of lchmod
Change-Id: Iccfddabe239b97a20b0b5302af4488482fffd86b
2011-07-11 14:40:17 -07:00
7f3a8c90b0 fix copy_file fail
Change-Id: I46e31ee17255e76a3c64a9e661dc74e636a345ec
2011-07-11 14:32:02 -07:00
e8bdefda33 build fixes and arm support.
Change-Id: I96fa6366c8bb1406d89f944f0fd1733bde565126
2011-07-11 14:13:43 -07:00
de7025e43c wtf
Change-Id: Id473833012794723c3fae22edc1cb436efdcda85
2011-07-11 13:27:34 -07:00
fd6a28be5d working restore
Change-Id: If5963348d2e9ac27164b1a929937a3ec3a4ecfa7
2011-07-11 13:26:14 -07:00
4f1c5e37f4 working restore
Change-Id: Id152f5f28b3836bae5884fcf2bec67b599e991c7
2011-07-11 13:25:04 -07:00
67700e791a dedupe for cloud backups
Change-Id: If88285763d89323a0417d9cc44cd161e906d2b69
2011-07-11 12:26:45 -07:00
3f2e286747 adding text output for battery stats wipe. just a confirmation that it completed successfully
Change-Id: I8c00521081b12f123c35239212f2b53dde3a7c8e
2011-07-10 22:48:39 -04:00
5e4f258ca2 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-10 01:30:07 +01:00
bc9dc6fc48 Merge "minui: graphics: finish updates for 32-bit framebuffer in recovery" into gingerbread 2011-07-09 22:05:10 +04:00
a2bc7245f7 Merge "[PATCH] [recovery]: Fix recovery mode display for RGB8888 display." into gingerbread 2011-07-09 22:05:00 +04:00
1c2238b3af minui: graphics: finish updates for 32-bit framebuffer in recovery
work around slight issue on Sensation device and Shooter, by using xres_virtual instead of xres to get the 4 extra bits needed. based of original changes from toastcfh and modified to not be hard coded 32 bit and work with 16 bit as well.

Change-Id: I15850a0969050598ffc14279b8b50c6fcb4682f7
2011-07-09 12:32:05 -04:00
128f131e41 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-09 01:30:06 +01:00
aaad77fc80 move choose zip option first in apply zip menu, update.zip is on main menu 2011-07-08 10:11:27 -07:00
9154b8cfd2 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-07-08 01:30:07 +01:00
933487868f Add missing commands to recovery init.rc
Wrote some missing items in recovery, most notably the serial number so that it shows up correctly on adb.

Change-Id: If430c0b78191c8d77f781aa605b5081571451775
2011-07-07 13:29:43 -07:00
e9ab999990 Merge "Add a new 'Show log' extended function. Could also be used to report last lines from log on error." into gingerbread 2011-07-07 23:59:59 +04:00
a75c067df4 Support overriding of the bml partition used for boot and recovery. This is not ideal, because that means that there are different flash_image binaries for different samsung phones. But as far as I know, there is no way to find out which bml device is boot or recovery.
Change-Id: I5e3b83dd9267a275def003182c1bd5d2cf585896
2011-07-07 12:55:02 -07:00
50732e3c67 backup and restore of /sdcard/Android (see getExternalFilesDir)
Change-Id: I6306464cdce4e3b48e0d109284e5606f65a84ee2
2011-07-07 12:44:05 -07:00
78f44e8bdf [PATCH] [recovery]: Fix recovery mode display for RGB8888 display.
Change-Id: If9cf141d89ef3b537d1228148cb324af7dcc11db
2011-07-07 02:02:51 -04:00
0b06fc0696 recovery: Ignore wipe command from bootloaders that always send it
Change-Id: Ia93e1aae4d07ff609a252ae60850c739b02f2969
2011-07-07 01:09:52 +01:00
67d358cf4e Add a new 'Show log' extended function.
Could also be used to report last lines from log on error.

Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>

Change-Id: I3d9e51f4e81e48f20120e2449ccde651efae8d07
2011-06-30 01:26:13 +02:00
718a2f7872 init.rc: Simplify logic for starting adbd in recovery
Always start adbd if ro.debuggable=1 rather than basing it on user preference
in persistent system properties.

Use new D001 product ID, which I just allocated for "android recovery mode"

Change-Id: I6f1eac5257eaad2e538c0a8dd549ad89219efa3e
Signed-off-by: Mike Lockwood <lockwood@android.com>
2011-06-29 10:22:04 -04:00
ca0fc46095 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-29 01:30:06 +01:00
b4261d9ddd hopefully fix the logic. also address that the tune2fs and mke2fs binaries provided by codeaurora is arm v7, and thus can not be included for all devices.
Change-Id: I9ca996c904579fdb5df9a5453d2f1b9448f505db
2011-06-27 17:54:16 -07:00
47591ce0d0 Revert "use BOARD_HAS_SMALL_RECOVERY instead of BOARD_HAS_LARGE_FILESYSTEM"
This reverts commit 5ab3281dbe.
2011-06-27 17:52:25 -07:00
31c3ccf531 Revert "reversed logic"
This reverts commit 7305f7d956.
2011-06-27 17:52:15 -07:00
6c88ec2e8b Revert "reversed logic"
This reverts commit 9e08693670.
2011-06-27 17:52:07 -07:00
eed82c0f81 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-28 01:30:07 +01:00
9e08693670 reversed logic
Change-Id: Ie29418d7e3d82345f82888ade3eabdf6af5865f6
2011-06-27 11:30:31 -07:00
7305f7d956 reversed logic
Change-Id: I8fb671556b6fdfac9b34d48106cb3365c80bbe5a
2011-06-27 11:29:55 -07:00
5ab3281dbe use BOARD_HAS_SMALL_RECOVERY instead of BOARD_HAS_LARGE_FILESYSTEM
Change-Id: I7fe8bf226bdcf6429df62ae7fee82b5dabe6725b
2011-06-27 11:06:10 -07:00
b986fe24b4 Revert "Reverts: http://review.cyanogenmod.com/#change,6130"
This reverts commit a42d2b1e24.
2011-06-27 11:03:04 -07:00
aee5f85b29 fix up libreboot dependency to librebootrecovery
Change-Id: If39697943554538c938edaa478976eed9feb82d7
2011-06-27 11:02:44 -07:00
40fd4565d7 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-27 01:30:06 +01:00
a42d2b1e24 Reverts: http://review.cyanogenmod.com/#change,6130
The system() call implemented in bionic/libc/unistd/system.c
depends on paths.h which sets _PATH_BSHELL to "/system/bin/sh"
which is incorrect for recovery - recovery cannot
depend on /system being mounted or even sane because /system
could be corrupt when recovery is used.

We need _PATH_BSHELL to be pointing to /sbin/sh - and
therefore bootable/recovery has its own __system() call
implemented in bootable/recovery/libcrecovery that sets
_PATH_BSHELL as well as makes sure environ is used in
the call to execve.

Change-Id: I2e5fd9c259e4fd0a9aad826a297fd3233a50a7c1
2011-06-25 18:41:05 -04:00
9759ede732 Use the callback function in the call to mkyaffs2image() in _wrapper
Change-Id: Iee385a602e33a44dfa0deee8af49133f16f09d2c
2011-06-25 18:40:18 -04:00
9d2629c1c4 Allow applying an OTA package manually from cache.
Change-Id: I8f78377555c658a992ca95cadf11b67ddc93fed8
2011-06-24 11:53:58 -07:00
3dbe66b71d Get the correct line_length.
Set the BPP and other fields and write it back, so the line_length comes back correctly.

Change-Id: I85e4e8223c79b9394ae1fb609b3026de62027ab8
2011-06-24 11:06:01 -07:00
fb04b87002 fix adb root in recovery
recovery's init.rc was missing lines that made adb root work.

Change-Id: I300e6997e3b5cb9c7b542b2012eed61deb2550f1
2011-06-23 15:30:34 -07:00
9d1bcdf7b8 Graphics can handle stride != xres, and BGRA support.
Change-Id: Ifee94ac08028e62a40241a089ac7c36346fea3a3
2011-06-22 15:04:00 -07:00
7e58b65efb Fix starting adb in recovery mode
Change-Id: I8444f44d3194ff16ce54121633d5b255231393f5
Signed-off-by: Mike Lockwood <lockwood@android.com>
2011-06-19 02:52:01 -04:00
eb1ecab9bb Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-17 01:30:06 +01:00
11cff33332 bug fixes
Change-Id: Iadce53c6fbd4fe07d899e18c94198ec2e3a60f0d
2011-06-16 17:05:34 -07:00
fb3bd71038 fix crash bug.
Change-Id: I1afbc75815ffc72508942b73e40f67307f330ddf
2011-06-16 14:13:02 -07:00
e909c69169 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-16 01:30:06 +01:00
7905c80940 bug fixes
Change-Id: I1125db9cb1a12a95060f7673965fd40994a78c5b
2011-06-15 00:00:55 -07:00
fcb87af735 fix build
Change-Id: I3701f71ed9ecf5b6879e12ab6f618d5b678ef2f3
2011-06-14 23:44:39 -07:00
55e5e7b59a cleanups for tar and /data/media support
Change-Id: I4afe3a8d4484f91b1e689d7b3aa4f137acd66e93
2011-06-14 23:39:59 -07:00
16cfb3c72f Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-15 01:30:04 +01:00
7126ef404c use new libreboot static lib for rebooting
relevant commit is here: http://review.cyanogenmod.com/#change,6128

Change-Id: Id8587cba4017c322b3a5b89c1f994ade684f424a
2011-06-14 15:53:57 -05:00
2457adcdf7 Do not duplicate reboot.c
Change-Id: I2ed41ffd14372bec9e18865cf299e15abc67d689
2011-06-14 10:57:01 -07:00
0e961cd47a Fix up tune2fs republish bug
Change-Id: I43d77d52e73071777ee06bad360fe33f1cb747a0
2011-06-13 19:51:00 -07:00
5583712d6f Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-11 01:30:05 +01:00
4fbfc4610e 4.0.0.2
Change-Id: I6db9589e90f78e83201ebda90701b364223274d1
2011-06-10 10:52:31 -07:00
38a921435a make tar backups opt in.
Change-Id: Ib01131f3a65ce4114e73abe2c7ba42263d281844
2011-06-10 09:45:52 -07:00
94caefedb7 move the sdcard symlinker into process_volumes
Change-Id: I863fbeadea8428c7809260522316c493a6ea33ea
2011-06-10 09:17:30 -07:00
2e0964bed1 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-10 09:13:00 -07:00
4eff651c83 4.0.0.1
Change-Id: I0824973915621b86b41bace2abeeb5012cd1ffef
2011-06-10 09:12:52 -07:00
1f40b86175 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-10 01:30:05 +01:00
14d9e75577 added the efs partition to the do not format list since this holds the imei info.
Change-Id: I2644327c1dbaa63420b7eb7b1bce10377c0e0837
2011-06-09 18:37:28 -04:00
4d8c033203 also fix up the /sdcard symlink on startup
Change-Id: Ie7647b3fbb2543761d59b8c33ceeea36e3221c32
2011-06-09 14:19:04 -07:00
0e6b3f22ca Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-09 21:18:34 +01:00
967e15c44d 4.0.0.0
Change-Id: Ie7cf932287d5c7a2fed6cb7341a5b86d5baec2d8
2011-06-09 11:04:32 -07:00
5082299146 tar nandroid and /data/media support.
Change-Id: I9405e701887fc83c422c63c1dbf5ff087fff880d
2011-06-08 19:03:27 -07:00
5a4e03d120 am f84b2524: am 6ebedf00: am 82da01d6: Merge from gingerbread
* commit 'f84b25243d7ebeaca8424171f5ca3b192cc76d80':
2011-06-08 14:47:00 -07:00
7f72ad7934 am a94d9548: am 1117c69f: am 7172eb7b: Merge "Mute unharmful build warning at the top of the build log:" into gingerbread
* commit 'a94d954862fab26f6159ed7bb836ba6758a569fd':
  Mute unharmful build warning at the top of the build log:
2011-06-08 14:46:59 -07:00
f84b25243d am 6ebedf00: am 82da01d6: Merge from gingerbread
* commit '6ebedf0053ccefd414e5887db316f84bd8f6c44c':
2011-06-07 13:23:26 -07:00
a94d954862 am 1117c69f: am 7172eb7b: Merge "Mute unharmful build warning at the top of the build log:" into gingerbread
* commit '1117c69fe40dccfa6090d184094c4a6d407ab8d6':
  Mute unharmful build warning at the top of the build log:
2011-06-07 13:22:51 -07:00
5f77b7d715 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-07 01:30:05 +01:00
ebe7a1dcf6 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-06 02:13:04 +01:00
c56768cfb1 3.2.0.1
Change-Id: Ic043cdf147a6bb9f07ff0b1616d9f8fe8d9546dd
2011-06-05 16:28:25 -07:00
cdcb773cea Rename format_ignore_partitions to a forbid_format
There is a max length for system property names at 32 characters. The
old recovery property name was over this length.

Renamed the property to one much shorter so it is read properly.

Change-Id: Iecadd1218a64cab0c4fb94c5e910b920217580f1
2011-06-05 16:40:00 -06:00
ab0f3f79d6 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-06-04 03:00:06 +01:00
b3aac3c367 Merge "Fix 6 extentedcommands declaration warnings" into gingerbread 2011-06-03 06:44:41 +04:00
6ebedf0053 am 82da01d6: Merge from gingerbread
* commit '82da01d6a32c4fbfe57155c119d4669d7faba438':
2011-06-01 14:23:11 -07:00
82da01d6a3 Merge from gingerbread
Change-Id: I30902cdb19698f88a1ea57cf8c7667ef867d13a8
2011-06-01 14:08:15 -07:00
1117c69fe4 am 7172eb7b: Merge "Mute unharmful build warning at the top of the build log:" into gingerbread
* commit '7172eb7b623f4b30f5a709d639fcd3fb51cd6220':
  Mute unharmful build warning at the top of the build log:
2011-06-01 08:06:14 -07:00
7172eb7b62 Merge "Mute unharmful build warning at the top of the build log:" into gingerbread 2011-05-31 14:03:36 -07:00
8d2e1defb8 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-05-31 03:00:05 +01:00
01143a5630 remove logging, fix bug
Change-Id: Ie300222a3754a1ed7de5851a2298526a416da5d3
2011-05-30 15:22:04 -07:00
b2d30187d6 remove logging, fix bug
Change-Id: Ia7d0f5e7cdf64235bb2142d9143fff3f289ad605
2011-05-30 15:21:44 -07:00
88efbfb82b Fix 6 extentedcommands declaration warnings
Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
2011-05-30 13:27:05 +02:00
195e06be59 allow flashing only bml8 if explicitly specified.
Change-Id: Ie0d282105413b3a448436c9ee69206718e924754
2011-05-29 19:33:42 -07:00
aff130d843 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-05-30 03:00:05 +01:00
cf5195aa79 fix boot image not flashing properly, prevent the error in the future.
Change-Id: I6163e5a519ef28e9e9ea12d5a46d525d1d9d8fb2
2011-05-29 18:45:42 -07:00
ef5994fe29 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-05-27 03:00:05 +01:00
30712302e0 more logging
Change-Id: I2f5f37751f16c8b50f5c3ccf1eb56b9b52f44c6b
2011-05-26 17:49:56 -07:00
4187347329 fix formatting
Change-Id: Ic6162e5044b50544fab2d5aa83e1e22f373419d7
2011-05-26 17:30:43 -07:00
0bf1c6e598 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-05-26 22:19:42 +01:00
7adeadce47 fix up some implicit declarations
Change-Id: Ia98bb5bea04a9cb87bf1993687e7f91f46022509
2011-05-26 11:47:56 -07:00
e62132bb6d more fixes
Change-Id: Ic55d94ef69b6b8ea4ec2a6df708a9444e9d5f4e5
2011-05-26 11:29:29 -07:00
8a6bc77423 test
Change-Id: I25bd6846aea09247459c89ba98e6ac34c3debaa3
2011-05-26 11:14:15 -07:00
d3e66fed8b Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-05-26 00:00:10 +01:00
d79b7541f3 whoops
Change-Id: Ided86fe1991e5d9d6a707465429ec35ccc09743a
2011-05-25 10:47:41 -07:00
b7b7b37457 Mute unharmful build warning at the top of the build log:
diff: out/target/product/generic/obj/PACKAGING/updater_extensions_intermediates/register.inc.list:
No such file or directory

Change-Id: I269b1703b6091b343db45b1c5cdd0962c738788b
2011-05-24 16:11:05 -07:00
28a08efe15 Reconcile with honeycomb-release
Change-Id: I1205ca405fdaf586ebc349fbe83969e9694fab60
2011-05-20 12:45:51 -07:00
0b4eac9e01 also set UPDATE_PACKAGE in updater for old recoveries
Change-Id: I90e3feb0c1655279d58751ce800f299d9b4f3d03
2011-05-16 13:32:01 -07:00
666053ed26 3.1.0.1
Change-Id: Ia3115a520922254565532bbbb1e9aba6c680e80b
2011-05-16 10:04:53 -07:00
63605f1d45 Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-05-15 18:49:22 -07:00
20b516a408 set the env for UPDATE_PACKAGE (the source zip) for update-binary. This allows shell scripts to use the source zip.
Change-Id: Ia8118b31408f687780dd45e14f540a7e76619cba
2011-05-15 18:48:17 -07:00
49553c7561 Do not close the zip archive prematurely. It may be accessed later for a firmware update.
Change-Id: I31c298f75bbcdc7998221aa2b3aa334926343139
2011-05-13 13:01:26 -07:00
9ad8ba21b3 Allow per device unsafe-to-format partition list
The change switches is_safe_to_format() from a hard coded list
to a list that can be overwritten by system property.

Change-Id: Ie536044a912c3e88462831851d288a60fdc30e2b
2011-05-12 17:11:31 -06:00
4d5109cfa8 update to 3.1.0.0
Change-Id: I86d5aa2651c297ddf03279269da0c23819a06be1
2011-05-12 13:46:19 -07:00
e44b41a770 am c2a158db: Merge remote branch \'goog/honeycomb-mr2\' into honeycomb-LTE
* commit 'c2a158db9588e6ad290dd0f9171a190609900387':
  delay accessing misc partition until its device exists
2011-05-09 10:53:22 -07:00
c2a158db95 Merge remote branch 'goog/honeycomb-mr2' into honeycomb-LTE 2011-05-08 22:31:27 -07:00
54815c9dc9 Use TARGET_RECOVERY_PRE_COMMAND before calling __reboot() recovery
For the Power menu,
frameworks/base/core/jni/android_os_Power.cpp#L180
already uses TARGET_RECOVERY_PRE_COMMAND if
TARGET_RECOVERY_PRE_COMMAND is defined in the
BoardConfig.mk for a device to make a system() call before
calling __reboot() for recovery. This commit adds
the same thing to the other places that we know we are
getting into recovery using __reboot().

Change-Id: Ifd0394fed1e87b63d80d95e0e2a049004518e27e
2011-05-07 15:36:56 -04:00
c636b7300b am 90588820: delay accessing misc partition until its device exists
* commit '90588820b7110acf142d17457f0d10cd7cb57a8a':
  delay accessing misc partition until its device exists
2011-05-04 12:46:12 -07:00
90588820b7 delay accessing misc partition until its device exists
When the misc partition is on an emmc device, recovery can get started
and try to access it before the kernel has actually created the
device.  Try statting the device before reading or writing it; delay
up to 10 seconds waiting for the device to exist.

Change-Id: I93256db4b047c76020490e8a3dc76b8ade643291
2011-05-04 11:17:35 -04:00
f4bb554ee9 delay accessing misc partition until its device exists
When the misc partition is on an emmc device, recovery can get started
and try to access it before the kernel has actually created the
device.  Try statting the device before reading or writing it; delay
up to 10 seconds waiting for the device to exist.

Change-Id: I988442d5701394d7152bfab3c571e7548c364f61
2011-05-04 11:07:48 -04:00
wjb
cea6eba92d recovery: display mount point when confirming format
Change-Id: I474a511774b9e7ecf92f9fcedb1952d4c0adfdbc
2011-04-30 21:04:04 -04:00
cde585e3de Merge "Try to mount vol->device2 partition to UMS." into gingerbread 2011-04-27 09:56:27 +04:00
df3004bd16 Try to mount vol->device2 partition to UMS.
Stock sd-card that ships with LG-P500 formatted with no partitions.
This issue can be handled with device2 in recovery.fstab.
But UMS didn't.
We will try to mount second device (if it was defined) if first failed.

Change-Id: Ia8b58b9fdfa3e63f703a1dd5870cb76936cec88e
2011-04-26 19:15:22 +03:00
9c4c8e2c66 bml_over_mtd: Take care of bad blocks on "boot" partition for Samsung Galaxy S Phones.
The Samsung Galaxy S bootloader apparently expects the kernel to be flashed to BML-managed flash - bad erase blocks will be mapped from a reservoir area.
CWM however just skips bad blocks, the usual procedure for mtd-accessed flash.
Consequently, the bootloader sees a corrupt zImage, and will usually crash when the kernel initializes.
This of course will only happen when the "boot" partition has bad blocks.

This patch was written by "eifert" and adds a tool called "bml_over_mtd" for flashing boot images which takes care of bad blocks and maps them to a reservoir area, like BML does.

Change-Id: If570717a19b879d47d70d937a0751cd85853eacd
2011-04-25 11:16:41 -07:00
6a97396572 3.0.2.8
Change-Id: Icce5373f73f349c07bad29763803ba919cf64dc1
2011-04-24 20:16:39 -07:00
7364e82a5f format .android_secure on RM data wipe.
Change-Id: If417334263f577f0f1ca9a8c5bf6b63582dbb09f
2011-04-23 19:01:16 -07:00
1f1a274ecc 3.0.2.7
Change-Id: I43e32be031bf7803ca3ef3c8e77e7955218fd798
2011-04-23 16:35:19 -07:00
803896f62c Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-04-22 12:12:33 -07:00
f573510b50 bml fixes
Change-Id: I442ef3c155bab36db578ca5735215aedda353c29
2011-04-22 12:12:32 -07:00
f1bde36572 fix bug where the wrong SD Card block gets partitioned. rely on the ftsab to glean the sdcard mmcblk
Change-Id: Idee8d3e147ba91c45a9f9fe91126c7b5a19ee38d
2011-04-22 11:26:03 -07:00
cfd256a332 delay accessing misc partition until its device exists
When the misc partition is on an emmc device, recovery can get started
and try to access it before the kernel has actually created the
device.  Try statting the device before reading or writing it; delay
up to 10 seconds waiting for the device to exist.

Change-Id: Ib9bf6c35fa2c28fc43aa7550aaaffb76c9f6e120
2011-04-22 09:33:14 -07:00
907ed71a5c yes/no only, yes before no 2011-04-18 03:54:24 +01:00
eee085415f remove old chargemode crap
Change-Id: I6ca88be821ebb713a796251f416b02c1f7144c44
2011-04-17 15:56:30 -07:00
fdd4766c1e Revert "allow precise device detection"
This reverts commit ed7d296dfa.
2011-04-17 00:49:15 -07:00
ed7d296dfa allow precise device detection
Change-Id: Ie837500d459c95df0b1a5f849b3eba718cf8cf09
2011-04-16 13:45:53 -07:00
179b2d9895 make write_raw_image able to take a blob
write_raw_image() can now take either a blob or a filename as the
source.  The blob format eliminates the need for a temp file.

Change-Id: I0c6effec53d47862040efcec75e64b7c951cdcf7
2011-04-12 16:48:49 -07:00
469243e536 save a last_install file with the result of the last package install attempt
When installing a package, create /cache/recovery/last_install, which
contains the filename of the package and a 1 or 0 for success or
failure.

Also, don't mount ext4 and vfat filesystems as read-only (on devices
where /cache is ext4, we need it to be read-write).

Change-Id: I0cf2a1921bbd65e06343aa74e2006577fac77c2c
2011-04-12 09:28:10 -07:00
3a7dc29b24 Merge "add offmode charging for htc" into gingerbread 2011-04-12 00:36:22 +04:00
bab66b40f7 Merge "recovery: Prevent the users from doing stupid things." into gingerbread 2011-04-10 21:30:40 +04:00
6944713e92 add offmode charging for htc
Change-Id: I76ea278c10658e16bf864a8290edc95e4232970e
2011-04-10 10:20:53 -07:00
7a52627720 Recovery: Fix improper variable check
Change-Id: Ib2bb105c204f4f3f88d9a10056d368d6f54548ed
2011-04-09 20:32:48 -04:00
0d87851037 recovery: Prevent the users from doing stupid things.
Don't allow formatting of special partitions like radio, bootloader,
or misc. No sense in formatting recovery from recovery either dawg.

Change-Id: I0f935aad103574b17be237993730afaeae623871
2011-04-09 14:49:09 -04:00
814a934c8f Recovery: Fix keys for many new devices
cwm 3.0.2.4 had the bad habbit to bind back key to enter,
which is the same function as power key, when there is no
select-button on that device.

many many new (htc) devices got: home | menu | back | search

back should be always back. having back working as enter
button confused the shit out of me.
home/menu was not used. i bound up/down highlight movement to it
back is fixed back. search on the other hand is replacement enter.

so, you can control the whole recovery with those 4 easy-to-reach
keys now. on some devices power/vol+/vol- are kinda hard to reach.

if this patch breaks any other devices i am not aware off, please
handle this issue in another sane way.

Change-Id: Ic9c14e6ae7a8a0f1c9cf5c8895716e5357b3da0e
2011-03-26 18:51:18 +01:00
d2375719d5 reverse the logic cause it weirds me out.
Change-Id: I0203d0713c1cc3085d0df77da4b85c1b99a271de
2011-03-23 23:12:27 -07:00
3bf881539c Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-03-23 22:51:57 -07:00
ee9ab1969a 3.0.2.4
Change-Id: Ic727ec267f090bd8f9bc04f02e852184aecccc89
2011-03-23 22:51:53 -07:00
5615b2d46a Fix makefile fail
Change-Id: I47e0332d2c8aff8909cc5f0cc75195b1ed3fc688
2011-03-21 20:31:52 -04:00
3f26366993 Recovery: rearrage defines to fix recovery for mecha and
not break it for toastcfh

Change-Id: If6d4ced872bc04fc5d02803672c8279c82fe9ea3
2011-03-21 08:03:46 -04:00
faa477ec99 fix potential break that toastcfh found?
Change-Id: I590bf171a78380daaa9ea65b4ece726b64c7cd23
2011-03-20 15:44:48 -07:00
6d19f22c85 Recovery: Add support for filesystems >2gb
Add a  prebuilt static linked mke2fs with support for >2gb FS.
Add board_has_large_filesystem define
Adjust mmcutils for differences between busybox and static mke2fs

Change-Id: Ib02771ee161e8874b6840067dc8682fc63ad6513
2011-03-20 08:28:09 -04:00
67fa0c375f fix erroneous detection of device flash type when device is explicitly provided. fix bugs in mount generation.
Change-Id: I54a35390550b1384f12c4b12267029d77bef8fa3
2011-03-17 11:37:21 -07:00
3ed8e18721 am 4762633c: log which key a package verified against in recovery
* commit '4762633cf846d17516878303502b056b52353a5d':
  log which key a package verified against in recovery
2011-03-15 13:47:23 -07:00
4762633cf8 log which key a package verified against in recovery
Change-Id: I0d91b715d1eb9e45e2fce54bb93ba0abef92727e
2011-03-15 12:11:08 -07:00
201aa88cba recovery: mount /sdcard read-only
Change-Id: Ieffafe00cf82620057cacd0629cb60b0e6aad817
Signed-off-by: Iliyan Malchev <malchev@google.com>
2011-03-11 16:47:53 -08:00
90415aca67 am 6e4472ab: Have recovery reboot using the new android_reboot() function.
* commit '6e4472abbd3c7be9cd31d98a03df1e3b6fa92f40':
  Have recovery reboot using the new android_reboot() function.
2011-03-10 19:44:38 -08:00
6e4472abbd Have recovery reboot using the new android_reboot() function.
The new android_reboot() function is a nicer way to reboot the
system.  I can optionally sync() and remount read-only writable
filesystems.  This fixes bug 3350709.

Change-Id: Ic4c8676debd642e57bce3107b99dd810d90b6f82
2011-03-10 19:30:13 -08:00
f66088d2ce am 6ce4a326: don\'t reboot for inactivity if USB is connected
* commit '6ce4a326efae4abb108e19899f4d7776abc362da':
  don't reboot for inactivity if USB is connected
2011-03-08 23:53:35 -08:00
6ce4a326ef don't reboot for inactivity if USB is connected
(Cherry-pick back from master.)

Bug: 4071007
Change-Id: I28355c593770df678968185171bdd19dabe7f062
2011-03-08 17:51:14 -08:00
4cc533dd1c don't reboot for inactivity if USB is connected
Change-Id: Icba35da91167d30c446581afb47d0804e49964bf
2011-03-08 12:25:05 -08:00
b70fe3f76a am 68189f29: allow paletted RGB images in recovery
* commit '68189f2994690538b6e3bddc3788cb092cbda088':
  allow paletted RGB images in recovery
2011-03-07 15:47:04 -08:00
92796ec949 build "mount & storage" menu from fstab 2011-03-07 13:06:07 +01:00
59d86b4cf7 fix wimax backup for emmc
Change-Id: I3da8a3d9411b52e07bebe6214f86dd12ac98bb82
2011-03-06 15:18:48 -08:00
68189f2994 allow paletted RGB images in recovery
Recovery assumes any paletted images are in RGBA format.  Make it
handle both RGB and RGBA paletted images.

Bug: 3514884
Change-Id: I517cd571aa3f434dacacc33a774236260aec20ef
2011-03-04 17:13:16 -08:00
7e69e2cccc Merge branch 'master' of ssh://android-git:29418/platform/bootable/recovery 2011-03-04 00:29:22 -08:00
73bb6f749f convert recovery images to palettized PNGs
Cuts the byte size of the recovery images in half, roughly.

Change-Id: I3c45b5e58423b57faca83fc67b4e24e8d643c5b1
2011-03-03 16:52:06 -08:00
b7c91766da convert recovery images to palettized PNGs
Cuts the byte size of the recovery images in half, roughly.

Change-Id: I453a499e9937163c545dab3c552201882766e218
2011-03-03 14:43:13 -08:00
5ee98b20d0 for toast
Change-Id: I5dd56606ace68d77e244840941852571c05d36e0
2011-03-02 19:35:05 -08:00
65ad19c943 version
Change-Id: I34d22f72896a15abc4f0c75267dbcb78b1d6a33c
2011-03-02 12:36:14 -08:00
13ac7a473f fix build
Change-Id: If907795c670fb1ca7ba28bbfd40d21ce51405b7d
2011-03-02 12:36:10 -08:00
e734dad68c fixes
Change-Id: I28b58fec5ac92463bf189269267b8e1579dbc92c
2011-03-02 12:32:13 -08:00
be6d4d1052 change the default recovery assets to be in holograph style
Also remove the weird backwards compatibility thing for animations
with fewer than 10 frames.  Frames are always named "name01.png",
"name02.png", ..., no matter how many there are.

Change-Id: I7af64fdec1bfcdb0464998b735ec8d6c626ffe9d
2011-03-02 10:38:02 -08:00
fa265db3a3 remove redundant code
Change-Id: I6a24f89068c882b18973c9143a02768531b71ddd
2011-03-01 21:43:29 -08:00
c5ab2a34f9 remove debug code
Change-Id: I14a6657a6f875d4305ed72a163bf72e3e9c5dad1
2011-03-01 21:43:05 -08:00
e2b929ded1 forgot to check this in.
Change-Id: I97a7cf0b9bb296bff4b8a80f528082c0c409e9e1
2011-03-01 21:41:54 -08:00
6809c51f8d make recovery UI images more general; allow for installation animation
Change some of the UI parameters (# of indeterminate progress bar
frames, fps, etc.) from #defined constants to variables that can be
set by the device-specific recovery_ui code (via a new function).

Support overlaying different images on top of the base installation
icon to animate it.  Make the FPS control more accurate.

Change-Id: I9268b389b7ea6b3ed9e0c7eae37baf4272e60edd
2011-03-01 14:04:34 -08:00
a1f43bfd27 build break!
Change-Id: Ia33661ea1c735990528095038b93fd4ecb717341
2011-02-27 18:31:41 -08:00
978a0e25c4 logging
Change-Id: Id835419f1ed3d9cf9c946f73a35eddc3ac029a2c
2011-02-27 17:58:26 -08:00
ab1f8b836e more fixes for sammy
Change-Id: Ie11c673a204a328a82f767a2610c5f1d9a51233c
2011-02-27 17:28:30 -08:00
47d86a35bc option to specify usb_mass_storage device in device overlay 2011-02-27 17:07:53 -08:00
7161f35736 specify a type on the mount.
Change-Id: I610330e2971aaf235e0420fa7d4387e4f55b0015
2011-02-27 17:00:47 -08:00
33e37f3e5d check for bml too
Change-Id: Iff062f439c0daa0ce768c3853fd7c290e75b8d3d
2011-02-27 16:33:32 -08:00
d9fbe2f1ce Dont error spew if no misc partition is available.
Change-Id: Ic5d9c8dc936e8f9a4c61474cebeabb2eecc4446e
2011-02-27 15:54:03 -08:00
e8bc2c808c Support fs mount options.
Change-Id: I8b0dc79dd054c4d1af599d9b68b5478196bdd183
2011-02-27 14:00:19 -08:00
33fd0d0a70 Fix inc /datadata wiping from RM.
Change-Id: I983bf83a7baf1494c7ff26199591bb93fab5ae74
2011-02-27 12:42:24 -08:00
c007b961d7 am 8d43d940: am 2c273f00: store partition length in recovery.fstab
* commit '8d43d94065e88e00e1460841b43c7de584ee5585':
  store partition length in recovery.fstab
2011-02-24 20:35:19 -08:00
ee458bbf9b store partition length in recovery.fstab
Don't hardcode magical partition behavior in roots.c.

Change-Id: I587fc2c066575b51c11efd2e45a50f5b864df484
2011-02-24 18:46:44 -08:00
8d43d94065 am 2c273f00: store partition length in recovery.fstab
* commit '2c273f004e0504ae0389ad160ed2a92624873189':
  store partition length in recovery.fstab
2011-02-24 18:38:48 -08:00
2c273f004e store partition length in recovery.fstab
Don't hardcode magical partition behavior in roots.c.

Change-Id: I587fc2c066575b51c11efd2e45a50f5b864df484
2011-02-24 18:34:36 -08:00
75b2fa023b Merge "Added Power off capability" into gingerbread 2011-02-18 23:28:39 +00:00
2810ceda34 store partition length in recovery.fstab
Don't hardcode magical partition behavior in roots.c.

Change-Id: I587fc2c066575b51c11efd2e45a50f5b864df484
2011-02-17 15:55:21 -08:00
a9f0e7fdfe remove unused defines. dont try to mount boot if it is emmc or bml either.
Change-Id: I835f74785938be940111f03a6b092b926681d745
2011-02-12 10:21:11 -08:00
c7ef9af5d7 Change-Id: Id6ee1fed1eebbaa6d3a9e6117910f00a56378da4 2011-02-09 16:32:42 -08:00
49ee9a8b09 Defer to fstype2 if found. Use auto fs if two fstypes are specified
Change-Id: Id6ee1fed1eebbaa6d3a9e6117910f00a56378da4
2011-02-09 16:15:54 -08:00
64d79c6531 Support multiple file system types.
Change-Id: Icd89a7ce14ef7948dbd25bfbb17ff9d930514b00
2011-02-09 06:13:30 -08:00
4c05d95112 Fix x86 build.
Change-Id: Iada6268b0a72ee832113ea397334cc7950a37051
2011-02-08 19:51:07 -08:00
28fee5a1b2 Merge "Add support for devices that have an upside-down mounted display." into gingerbread 2011-02-06 22:12:49 +00:00
6d0604bf34 Add support to mount /boot for systems that have a mountable /boot.
This is checked at runtime to see if /boot is a mountable parition (i.e not mtd), if so it adds an entry into /etc/fstab.

This will allow us to mount /boot from an edify script and push certain files without completely imaging the parition which can contain other files such as the bootloader (u-boot), and recovery kernel and ramdisks as is the case with the encore (NookColor)

Test on NookColor and passion.  Correct entry was added to the NC and not added to the passion as expected.

Change-Id: I9850dee866b77653bf400bb5193905e55da3f25f
2011-01-28 13:42:14 -07:00
6da1abbc38 am 5df22d03: am 5cae445e: make recovery reboot after 2 minutes of no activity
* commit '5df22d03d2e7c6de213d83a58e0af39c42f839ca':
  make recovery reboot after 2 minutes of no activity
2011-01-25 13:56:07 -08:00
5df22d03d2 am 5cae445e: make recovery reboot after 2 minutes of no activity
* commit '5cae445e43c5928daba0a76745b0dd2657274eda':
  make recovery reboot after 2 minutes of no activity
2011-01-25 13:53:52 -08:00
5cae445e43 make recovery reboot after 2 minutes of no activity
If recovery sits for 2 minutes in prompt_and_wait(), and you've never
turned the screen on via the magic keypress, go ahead and reboot.  (We
used to assume that the user could pull the battery to get out of this
state, but on devices with nonremovable batteries...)

If you've ever enabled display of the log/menu since recovery started,
we assume you know what you're doing and will stay in recovery until
you choose to reboot.

Bug: 3387873
Bug: 3387274
Change-Id: I041621e5db132df9a925e6808845a7c45e1b427a
2011-01-25 13:50:16 -08:00
80abd51dbc am da993fcf: am 8d58c957: Merge "Free allocated struct after freeing field"
* commit 'da993fcf2665102435b05d6b20a4c4e8f8bd3b8f':
  Free allocated struct after freeing field
2011-01-21 16:15:02 -08:00
da993fcf26 am 8d58c957: Merge "Free allocated struct after freeing field"
* commit '8d58c957036835db148acc4e506633a016dc6c7e':
  Free allocated struct after freeing field
2011-01-21 16:12:03 -08:00
1966aaf4e6 Merge "remove encrypted filesystem code from recovery" 2011-01-21 13:12:30 -08:00
8d58c95703 Merge "Free allocated struct after freeing field" 2011-01-20 07:06:02 -08:00
8f132ed870 Reserve the last 16 Kbytes of /data for the crypto footer.
When formatting /data, if it's an ext4 filesystem, reserve the
last 16 Kbytes for the crypto footer.

Change-Id: I7b401d851ee87732e5da5860df0287a1c331c5b7
2011-01-19 17:12:47 -08:00
862c83bb31 Free allocated struct after freeing field
Free allocated MtdReadContext after freeing buffer field in struct,
not before.

Change-Id: I237920dc36115389cd2d6948e7a962dbec22fe56
2011-01-19 12:22:41 +01:00
b5d0bd024c Add support for devices that have an upside-down mounted display.
ZTE Blade is an example of this type of devices.
The original patch comes from Sebastian404 -> http://goo.gl/QC37W

Change-Id: Idffd97adf7da8a352617342bb6ff2161e6eac3a5
2011-01-19 11:15:08 +00:00
540d57f25a remove encrypted filesystem code from recovery
This was never used; encrypted filesystems are being done a different
way now.

Change-Id: I519c57b9be44d001f0b81516af7bfc252069892b
2011-01-18 13:36:58 -08:00
066a1027a4 Use raw partition functions for emmc
Change-Id: Ia5d9f18d43228a08f12633d432b299def8e26ae1
2011-01-16 06:29:31 -06:00
a25cf5ec4f Use erase_raw_partition for unknown named partitions
Change-Id: I84014a851ebdfb2c228cff43879580a761c22708
2011-01-16 06:05:22 -06:00
e06e539196 fix sd-ext backup and restore.
Change-Id: I346724f231bb29df2c0fa833df420620ab1be1b4
2011-01-16 02:33:04 -08:00
be3e6f13b8 option to allow recovery to use 24-bit graphics in UI
Add "RECOVERY_24_BIT := true" to the device's BoardConfig.mk to use
24-bit framebuffers in the recovery ui.

Change-Id: Iaede138bf7870becf237f12f1c0e49c9ff82d007
2011-01-13 16:43:44 -08:00
d646a6fa1d Added Power off capability
Change-Id: I545f8b73e84c5083d2d17b98f8edcdd612c0f78e
2011-01-10 06:14:21 +01:00
49396b79b5 Update make_ext4fs arguments in roots.c
Change-Id: I835e55fb80add6a74cd4d99f77b2528829d9a349
2011-01-05 17:19:37 -08:00
53c9bd8b10 Refactor nandroid so the availability of boot backup is determined automatically. Boot backups are also no longer assumes to be on raw partitions, as they may be on a VFAT partition or someting different, such as in the case of Nook.
Change-Id: I036befb44f0d873fde02485e34aab14faf8bfe8d
2011-01-04 11:38:31 -08:00
d8e21c3712 Add the volume command for seeing the current recovery.fstab. Support crazy HTC chargemode.
Change-Id: I26a6e83dc5704aa03ab3aa078f24f8943cf13614
2011-01-04 10:46:55 -08:00
b4c5fd6305 Support for ext2 and ext3 update-binary.
Change-Id: Ide34392bd8ac56878aa3e992b275a39d6b6bc7cf
2011-01-02 22:54:31 -08:00
9f52e5f23b fix android secure formatting
Change-Id: I617b8c453aad6d306cf8ddbc1a067c59ead56573
2011-01-02 14:11:24 -08:00
67c381a6fa 3.0.0.4. Provide an error message if an Amend zip is provided.
Change-Id: Ia740686a138cff01de2c1475acc0abccb18d9c2d
2011-01-02 12:26:35 -08:00
949f3b34ee Merge branch 'gingerbread' of git://github.com/CyanogenMod/android_bootable_recovery into gingerbread 2011-01-01 20:03:39 -08:00
f1cb0d5b35 fix ums mounting
Change-Id: I97316668fe3e4447a04cd9f189b0d3d89cd97d9f
2011-01-01 20:03:30 -08:00
ad10e56863 fix nandroid-md5.sh executable bit.
Change-Id: Ib90872e1ff341cc913de8ed3577738efd2428f61
2011-01-01 18:50:09 -08:00
7aa8ef9abc fix executable bit on e2fsck
Change-Id: Iedc3ead52645af5c104642e2eb78f3578fb7b8fb
2011-01-01 18:26:49 -08:00
a25deae3ef fix wimax
Change-Id: Ieff7638293e01546baf382d9c8a5b798cff46331
2011-01-01 18:17:48 -08:00
f12df71ffb fix nandroid linkage issue
Change-Id: I36998f2e94ad1ead656c6374c551d5e02e2db219
2011-01-01 18:16:01 -08:00
3affbec593 fix up boot formatting. remove depracated function.
Change-Id: I9d707e62b1752079ec1b669a3800dbf12e035ead
2011-01-01 18:10:11 -08:00
2e45449ef3 more logging
Change-Id: I77a7198808133e5f0a6d8de1f5e716aecf31c0ae
2011-01-01 18:06:17 -08:00
1375df75ff fix bug
Change-Id: Id38cf292fd93f5a53552c80c48d9281701b88ce0
2011-01-01 18:04:44 -08:00
a8708c6044 readd ext2/ext3 format support.
Change-Id: Ic21197df8ff53fdc8ffd3dc1947bd2ecb475eda8
2011-01-01 18:00:27 -08:00
da32b54f85 readd ext2/ext3 format support.
Change-Id: I58652abaea8f7a52b70bc1b14aec5b530fe70382
2011-01-01 17:55:22 -08:00
29a7891204 3.0.0.2
Change-Id: I4705196b5bf8e66e4ac409a027650be9ce491f4c
2010-12-30 23:17:28 -08:00
10a91b0bf2 Merge branch 'gingerbread' of https://github.com/jwise/android_bootable_recovery into gingerbread 2010-12-30 23:17:04 -08:00
5a3f1d8af5 Erase WiMAX device before restore. 2010-12-31 02:16:00 -05:00
05d4a09aba Fix up for property_get in recovery, which appears to have slightly different semantics. Durr. 2010-12-31 02:05:35 -05:00
15b06184cd cwm: set sd-ext label
Change-Id: I963924083f1f6de17effafa80fb6f7fe003b304d
2010-12-30 22:49:34 +01:00
ebc5aab351 3.0.0.1
Change-Id: Ie38f59158f6ada921e9be4e5a8e7cd89207225d5
2010-12-30 11:41:31 -08:00
ca889ec844 WiMAX backups have their serial number in them, and messages now say WiMAX instead of wimax. 2010-12-30 02:48:25 -05:00
5b7f34a2d8 wimax restore should not be on by default
Change-Id: I1e1869e615905ce6dbefd0b1a8e64414f619508e
2010-12-29 23:36:03 -08:00
1f76a5da6b Add support for wimax imaging
Change-Id: I2f14918f3ffb37fe94bab469e1d89a9874d89d18
2010-12-29 23:03:32 -08:00
264f549b7d Update arguments to make_ext4fs
Change-Id: Id96e98da76b3091987b01651f980797b1d6b49d8
2010-12-29 14:18:26 -08:00
7501798fab Fix nullpointer when recovery.fstab does not define a "misc" partition
Change-Id: I57437e3c637a1c619d254a3fc025db19ffe53c10
2010-12-28 23:54:29 +01:00
c8ff793bf4 fix build break
Change-Id: I8bc7dbe3a3c0ad09b032f332317e55ed2ebd28e3
2010-12-21 15:16:05 -08:00
1e6d772f35 Merge remote branch 'github/gingerbread' into gingerbread 2010-12-21 15:14:40 -08:00
03cf72a4f5 fix restore
Change-Id: I97d2bb16b364e701e9c37567b5c07e30be00fafb
2010-12-21 15:14:21 -08:00
cdb433af66 fix bml dump
Change-Id: Iaf3c6bd2f09b42dcb2474e700aee57c0aaacd996
2010-12-21 15:13:58 -08:00
745b5ff987 Use unique filenames for the pre ext4 convert backup.
Change-Id: I49ee96c454c826fc92c45f160c6d45cc5566f0a6
2010-12-21 00:58:43 -08:00
31b741174c Fix fstab generation.
Change-Id: Ibab3c93c55abcece80a89bbff620f164588baf96
2010-12-20 08:49:20 -08:00
bec0995afe ROM Manager is now powered by Edify,
Change-Id: I3857aa6591b743be146d87a4e97afdc9d9c765ed
2010-12-19 20:37:57 -08:00
33491accea Fix sdcard mount bug.
Change-Id: I2e448f3f0a0a4de39a8d1cd7db5dc8cd986d3229
2010-12-19 03:41:41 -08:00
4196e0fa5e bml devices that are using rfs are automatically upgraded to ext4. Version 3.0.0.0.
Change-Id: I069f0c5122e8d48ce311f519f08890d3e569dbb3
2010-12-19 03:38:29 -08:00
d0fff5633c Ifdef this a bit better.
Change-Id: I4528821563181ca7a64adff3a3128cea35447f09
2010-12-18 23:18:50 -08:00
5460f0c746 Automatically detect /datadata from recovery.fstab. Remove BOARD_HAS_DATADATA.
Change-Id: I28d3c7a6beaacd77c67c5af0ae3464acfd2572e3
2010-12-18 22:37:49 -08:00
5d80817f2b There was apparently a lack of carebear.
Change-Id: Ie65bce617b99985ab937602e1e30a97340b0dd5b
2010-12-18 22:29:27 -08:00
4995114d38 Add BOARD_HAS_JANKY_BACKBUFFER for terrible Galaxy Tabs.
Change-Id: I72e7a8aaf65c97d4cd2b77ff92cf7232f8c9e7a7
2010-12-18 21:58:43 -08:00
9765a037a1 Remove usage of BOARD_HAS_NO_MISC_PARTITION.
Change-Id: I5775f47fb1d5ef66e2461a0c53166af03354a6f6
2010-12-18 21:31:02 -08:00
7c1bffefeb Fix the build
Change-Id: I2ae07e94eb68dd261b3978671aec88c25cd2518e
2010-12-18 19:44:33 -08:00
bf4444f1fb Fix various bugs.
Change-Id: I46e3001e6857480a77253be24b1753b2e4d88e69
2010-12-18 18:57:47 -08:00
b643e4f3d0 Fix up fstab generation
Change-Id: I922183bc3de8d2b3bb7d1497725f2641a4358216
2010-12-18 18:39:39 -08:00
8637c73757 revert updater changes except what is necesary to do a write_raw_image on emmc devices.
Change-Id: I674c7b5873b7758bf15f0b55c34ec01513e6f23c
2010-12-18 18:18:44 -08:00
df1e406782 Merge from ClockworkMod recovery
Change-Id: Id5b312147173ced559a62d97029acede6c2f8766
2010-12-18 17:42:31 -08:00
0b7bbf29d5 recovery: Remove condition around get_root_mtd_partition
Change-Id: I2e763000f65aba342f1851c7e94778a815bbaa6f
2010-12-14 03:43:35 -05:00
d352233ab6 Added options for an internal SD card to be handled by recovery.
Exable uses in BoardConfig.mk:
	BOARD_HAS_SDCARD_INTERNAL := true
	BOARD_SDCARD_DEVICE_INTERNAL := /dev/block/mmcblk3p1

Setting BOARD_SDCARD_DEVICE_SECONDARY to the same value as
	BOARD_SDCARD_DEVICE_INTERNAL will allow the device to
	"fall back" to the internal SD card for other actions.

Change-Id: I2cf8ab4b1d385ac714f5b7416b915d059033d94b
2010-12-13 23:57:20 -08:00
16c0ace22b Fix write_raw_image on mtd devices.
Change-Id: I0fa64d4f4deaf8f067be3bd0b0bb963cf5af3f3f
2010-12-13 19:26:03 -08:00
134ead7537 fix up bmlutils some more
Change-Id: Ia11e917a6c0dc8164d599e02154f9f7b2934ed65
2010-12-12 16:54:41 -08:00
03a4f5ba0d supprot backup and restore of samsung kernels
Change-Id: I6deb5918f97ca5c5466b1d78369454b3452b89c0
2010-12-12 12:24:02 -08:00
cd8af06d64 whoops
Change-Id: I9c46bb443c43186fda1ae71e49278bd1a7d6aa6f
2010-12-12 02:53:21 -08:00
02c360501b Fix graphics corruption on some devices. BML restore needs to unlock first.
Change-Id: Ib6ede1dee0a0a4494319cfdb1613be2e89260874
2010-12-12 02:52:44 -08:00
8df69c0660 minui: useless code is useless
Change-Id: I288c82a647c4145a2569d5dec206b8ca89693e7c
2010-11-27 23:02:01 -06:00
229a543bb3 minui: clean up some stuff, and avoid multiple key events on N1
Change-Id: I7d26a406eb200c866b2fbc841424ac698f6d3bf3
2010-11-27 22:52:39 -06:00
517a16b98f Merge "minui: Add haptic feedback to virtual keys" into froyo 2010-11-28 03:54:03 +00:00
9397e322c3 Merge "minui: add support for virtual keys" into froyo 2010-11-28 03:53:44 +00:00
ddc2e39dcf fix fstab generation
Change-Id: I223a07fd0ce3c0d48b7f18f5c42ae204affe087a
2010-11-27 17:53:50 -08:00
d90ad5dedf fix no select button
Change-Id: I142d48156e166f9e5e7f3ad7c89c1829dbe2009a
2010-11-27 14:41:07 -08:00
3847a2ddd9 add missing file
Change-Id: I11948c0b4aece99e5cbdc32b39ba5b76d1b0ffb2
2010-11-27 13:36:17 -08:00
44bd4947d2 minui: Add haptic feedback to virtual keys
Change-Id: Ibd9298513626092297bff83f4914b436c4ffbb3a
2010-11-27 13:36:23 -06:00
ac731c88e3 minui: add support for virtual keys
Change-Id: Ie0e75a2fbccd42993a2f7c3d42ba38afea2d7679
2010-11-26 23:32:26 -06:00
9acb022ab8 recovery: Support board-specified font sizes and font-files
This, for example, is for an LDPI device:
BOARD_RECOVERY_FONT_INCLUDE_HEADER := ../../device/geeksphone/one/font_7x16.h
BOARD_RECOVERY_FONT_WIDTH := 7
BOARD_RECOVERY_FONT_HEIGHT := 16

Change-Id: I71d2f420b9668b5767c9b0b5d90e3e523c56e873
2010-11-27 04:08:06 +00:00
37d96f7414 2.5.1.3
Change-Id: Iae5d458edaedb90dd2422175a185a9b5725dbc74
2010-11-26 18:45:06 -08:00
0b23331f23 Added larger DATA size values for SD partitioning.
Used for systems that use internal SD partitioning for DATA storage.

Change-Id: I3274c196a7143143fccb806cff1665a6f40c1ce7
2010-11-19 10:28:56 -05:00
4123b58299 recovery: Autodetection of device flash type
Detect flash type at runtime rather than requiring this to be set in the
device configuration. The detection is based on the existence of /proc/mtd,
/proc/emmc, or /dev/block/bml1.

Change-Id: I464962a567022c5862c249f06d36c2d1cddeacba
2010-11-14 22:40:30 -05:00
158d25cae4 Supress "warning: comparison between signed and unsigned integer expressions" in minui/resources.c and mtdutils/mtdutils.c 2010-11-13 05:23:33 +08:00
7c50645a6c always build
Change-Id: I007eb15230e948074a1aad420ef0c3c6a2ae102e
2010-11-11 01:20:29 -08:00
e5c7e0eaca implement bmlutils
Change-Id: I8ec38a3b5e20e39b02c393d13e89142038ae3e82
2010-11-11 01:19:10 -08:00
12154200a7 fix up implementation of int get_partition_device
Change-Id: I142b15228322790892dd07b10d6a3f31440badc7
2010-11-11 01:16:14 -08:00
d771acbed0 Modify apply_patch to fail if trying to patch mtd on non-mtd devices.
Change-Id: I09c5bb5d12d838fdc4c4c6eb380021c9b3f3e33e
2010-11-11 00:00:45 -08:00
1b86754eaa Fix up updater to use the new refactored block device support.
Change-Id: I597f3d83ef14d2640192e0026a0fe1a93023bfc6
2010-11-10 23:52:09 -08:00
19447c0550 Refactor recovery's block device handling to work across variant hardware in a cleaner fashion.
Re add firmware update

Change-Id: I699ad22390ed14e597d17a7bcb32ad1b1af00b4b

support mmc misc

Change-Id: Iff02f8d03db6835f501d052140cebeefee521305

fix compile errors

Change-Id: I032edbd157a8a15f561bb83330c715ebaa008d18

fix compile errors

Change-Id: Idff3449be3376f22fceefc2c35637527f8df8f3f

Initial work to clean up the block devices.

Change-Id: I4be20ac124864a281be9cd116e211a2618404a27

all done

Change-Id: I0338f62f6a045556ebe90b0200685be113178319

fix up nandroid

Change-Id: I886f00271183e6d2921c080b0939341f2cf12a4d
2010-11-10 23:31:34 -08:00
fef77c0253 Changes to support Vision recovery. Fixing up a lot of bugs related to the CodeAurora mmc commit.
Change-Id: I9b71070fe41559a5d93d3c35efc3a511b7088e8e
2010-11-09 20:03:42 -08:00
7a77aec362 fix mmcutils usage
Change-Id: I04db586599af21f64174b0e656201c724bf82050
2010-11-09 09:23:15 -08:00
487821abe5 Merge remote branch 'github/eclair' into froyo 2010-11-06 17:59:05 -07:00
9456641236 2.5.1.1 2010-11-05 12:47:48 -07:00
70f7e8dbf0 am c5ebf1fb: am 5d6309e7: fix comparison of ECC stats before and after mtd reads
* commit 'c5ebf1fba2f870a4e9453721112900975c18e083':
  fix comparison of ECC stats before and after mtd reads
2010-11-04 07:20:28 -07:00
c5ebf1fba2 am 5d6309e7: fix comparison of ECC stats before and after mtd reads
* commit '5d6309e77f6055a9aec062dd991d071054726ebb':
  fix comparison of ECC stats before and after mtd reads
2010-11-03 15:18:12 -07:00
5d6309e77f fix comparison of ECC stats before and after mtd reads
ECC errors are found by comparing the result of ioctl(ECCGETSTATS)
before and after the read.  But if an error was found causing us to go
to the next block, we'd compare the stats before the *first* read to
the stats after the second (third, fourth, etc.) reads, so we'd read
to the end of the partition without ever succeeding.  Fix logic so we
compare the values before and after each read independently.

Bug: 3162777
Change-Id: I5a13abd7243d2afd1d21bd98cbb233e5124b2e80
2010-11-03 14:31:01 -07:00
02971af254 am 8521ef59: am 51266d13: clear recovery framebuffers on allocation; display icon right after ui_init
* commit '8521ef5965675da85c7bbbe9c8b86fe68716e855':
  clear recovery framebuffers on allocation; display icon right after ui_init
2010-11-01 10:40:33 -07:00
8521ef5965 am 51266d13: clear recovery framebuffers on allocation; display icon right after ui_init
* commit '51266d1397309978eac9b2e96035582454f0321b':
  clear recovery framebuffers on allocation; display icon right after ui_init
2010-11-01 10:38:12 -07:00
51266d1397 clear recovery framebuffers on allocation; display icon right after ui_init
Make ui_init() clear the framebuffer memory it maps in so the user
isn't treated to a visible flash of random bits on recovery startup.
Call ui_set_background() (to show the installing icon) right after
ui_init() to display something while device_recovery_start() is
working (which can take a second or two on some devices).

Bug: 3145331
Change-Id: I11e7859fab5847370ea4f4932c3fb1558af26c5d
2010-11-01 10:19:12 -07:00
1805cfe02e missing file
Change-Id: Ie87219d798f62128906fc6050ced7be5b4801426
2010-10-12 18:46:41 -07:00
815ca5d230 [recovery]: Add support for OTA upgrade on mmc devices.
Change-Id: I8f230dfa5be4e9f142765797d949e10434e1fdeb
2010-10-12 18:46:30 -07:00
0209a62c7d merge from froyo
Change-Id: Ic80ad93cd3b05d55ba8b4e16edaa59ee58f08f05
2010-10-12 11:39:35 -07:00
7c3ee270ce am 2d87023e: am 2c3539e4: save the log from recovery\'s last run in /cache/recovery/last_log
Merge commit '2d87023e77b20aa2196c8ceae833b33040b0dc57'

* commit '2d87023e77b20aa2196c8ceae833b33040b0dc57':
  save the log from recovery's last run in /cache/recovery/last_log
2010-09-30 11:25:31 -07:00
2d87023e77 am 2c3539e4: save the log from recovery\'s last run in /cache/recovery/last_log
Merge commit '2c3539e4d8251ad91e0b881253d39583680093e8' into gingerbread-plus-aosp

* commit '2c3539e4d8251ad91e0b881253d39583680093e8':
  save the log from recovery's last run in /cache/recovery/last_log
2010-09-29 13:46:06 -07:00
2c3539e4d8 save the log from recovery's last run in /cache/recovery/last_log
Also, don't lose the start of the log whenever a wipe cache is
performed.

Change-Id: I29999762854eb36d1ff2bc20b4183c9077b19777
2010-09-29 13:40:44 -07:00
1a32732db2 am 704fa750: am 9b125b04: handle old-style CACHE: packages
Merge commit '704fa75024467fb4e362537f7c341eb056e283b5'

* commit '704fa75024467fb4e362537f7c341eb056e283b5':
  handle old-style CACHE: packages
2010-09-22 13:53:57 -07:00
704fa75024 am 9b125b04: handle old-style CACHE: packages
Merge commit '9b125b04c6ba8f07d8aa6494d58917a596443dc5' into gingerbread-plus-aosp

* commit '9b125b04c6ba8f07d8aa6494d58917a596443dc5':
  handle old-style CACHE: packages
2010-09-22 12:06:24 -07:00
9b125b04c6 handle old-style CACHE: packages
Change-Id: I7bf52b56770c207ba1c8329243991b07ebb65779
2010-09-22 12:01:37 -07:00
6b26c882a8 am af78591c: am 2c3c5c15: Merge "mount sdcard only on demand; fix sideload installs" into gingerbread
Merge commit 'af78591c9a2aa8379c2d8528c31ea1eb813f6cae'

* commit 'af78591c9a2aa8379c2d8528c31ea1eb813f6cae':
  mount sdcard only on demand; fix sideload installs
2010-09-21 20:21:52 -07:00
af78591c9a am 2c3c5c15: Merge "mount sdcard only on demand; fix sideload installs" into gingerbread
Merge commit '2c3c5c15d15faf1c9fa074851c57d0afa2a40d28' into gingerbread-plus-aosp

* commit '2c3c5c15d15faf1c9fa074851c57d0afa2a40d28':
  mount sdcard only on demand; fix sideload installs
2010-09-21 20:01:51 -07:00
2c3c5c15d1 Merge "mount sdcard only on demand; fix sideload installs" into gingerbread 2010-09-21 20:00:18 -07:00
c18eeb874b mount sdcard only on demand; fix sideload installs
Bug: 3009493
Change-Id: I1a7f99fc41a6a7012742e82f8c06a0c75584890a
2010-09-21 16:58:10 -07:00
3d798835a3 am 8147ba85: (-s ours) am 93ca4fc6: use fs_type "emmc" instead of "block" for consistency (do not merge)
Merge commit '8147ba850b2e74dc950183e67c77a0da2b1a19b7'

* commit '8147ba850b2e74dc950183e67c77a0da2b1a19b7':
  use fs_type "emmc" instead of "block" for consistency (do not merge)
2010-09-21 14:46:43 -07:00
8147ba850b am 93ca4fc6: use fs_type "emmc" instead of "block" for consistency (do not merge)
Merge commit '93ca4fc6943a3ebf758c5db98531531b8fe92c98' into gingerbread-plus-aosp

* commit '93ca4fc6943a3ebf758c5db98531531b8fe92c98':
  use fs_type "emmc" instead of "block" for consistency (do not merge)
2010-09-21 14:37:10 -07:00
93ca4fc694 use fs_type "emmc" instead of "block" for consistency (do not merge)
Change-Id: Iab60665d9c6daef7893896a64b7f319120a5f8ee
2010-09-21 14:28:11 -07:00
cc8cd3f3ca remove the notion of "root path"; support mixed flash types
Remove the wacky notion of "roots" and "root paths" (those things that
look like "FOO:some/path" instead of just "/foo/some/path").  Let each
device specify its own table of available partitions and how to mount
them (needed for devices that use both MTD/yaffs2 and EMMC/ext4
partitions).

(Cherrypicked from gingerbread w/slight edits.)

Change-Id: I2479ce76b13e73f1d12035c89386c3a82b3edf51
2010-09-21 14:13:45 -07:00
0f1ad110f8 am 3dba40da: (-s ours) am d4208f9f: remove the notion of "root path"; support mixed flash types (do not merge)
Merge commit '3dba40da1e533c6f419857e4274d9d9dd55868b6'

* commit '3dba40da1e533c6f419857e4274d9d9dd55868b6':
  remove the notion of "root path"; support mixed flash types (do not merge)
2010-09-21 11:38:21 -07:00
3dba40da1e am d4208f9f: remove the notion of "root path"; support mixed flash types (do not merge)
Merge commit 'd4208f9f9d4e9f268ba1888c1fe879ee73eb7e47' into gingerbread-plus-aosp

* commit 'd4208f9f9d4e9f268ba1888c1fe879ee73eb7e47':
  remove the notion of "root path"; support mixed flash types (do not merge)
2010-09-21 11:34:39 -07:00
d4208f9f9d remove the notion of "root path"; support mixed flash types (do not merge)
Remove the wacky notion of "roots" and "root paths" (those things that
look like "FOO:some/path" instead of just "/foo/some/path").  Let each
device specify its own table of available partitions and how to mount
them (needed for devices that use both MTD/yaffs2 and EMMC/ext4
partitions).

Change-Id: I18b0a572a71c5e087e0b7ae11b1774388339bfd1
2010-09-20 18:07:31 -07:00
c9ebb58623 resolved conflicts for merge of 40f0d3b4 to master
Change-Id: If14ab094a8bb11106b0ea7fdf8736e5e4c223089
2010-09-17 16:07:14 -07:00
cb71c2f334 merge from eclair 2010-09-17 14:19:52 -07:00
e17a78ddda allow the parted and fix permissions tools to be optional 2010-09-17 14:17:57 -07:00
40f0d3b4e0 am d7d42089: remove unneeded partition roots
Merge commit 'd7d4208976125d114d0b8e44438e2417d5275098' into gingerbread-plus-aosp

* commit 'd7d4208976125d114d0b8e44438e2417d5275098':
  remove unneeded partition roots
2010-09-17 13:30:15 -07:00
d7d4208976 remove unneeded partition roots
Recovery itself no longer needs to access all these partitions;
manipulation of them is done by the updater binary.  This is a small
first step towards removing roots entirely.

Change-Id: I3fbcada32079a37db4cc097861dfa91e0a08da30
2010-09-17 13:02:48 -07:00
97e54ef573 am 1dcd2fd0: (-s ours) am 792b0071: do not merge - update to match ext4utils api
Merge commit '1dcd2fd0c7cc44cae279a5088241bdf15f084cb8'

* commit '1dcd2fd0c7cc44cae279a5088241bdf15f084cb8':
  do not merge - update to match ext4utils api
2010-09-15 19:49:56 -07:00
1dcd2fd0c7 am 792b0071: do not merge - update to match ext4utils api
Merge commit '792b00712bb1411d3b0583bcea95b43b3107fb95' into gingerbread-plus-aosp

* commit '792b00712bb1411d3b0583bcea95b43b3107fb95':
  do not merge - update to match ext4utils api
2010-09-15 18:07:22 -07:00
dc49ce453e add missing sparseness parameter
Change-Id: Ie6e309b127e80cd6475f1deaa5dbadf9f5cc2746
2010-09-15 18:05:10 -07:00
792b00712b do not merge - update to match ext4utils api
Change-Id: I9d34e491022d7dfed653a861b0728a0a656f1fbe
2010-09-15 18:03:58 -07:00
6c3e03b3c5 resolved conflicts for merge of 85bcf776 to master
Change-Id: Iab4f25702a5a62b9172f81fd543a8240a0e603c3
2010-09-15 17:51:50 -07:00
a66c32ab1d resolved conflicts for merge of 9f89b0e4 to master
Change-Id: Id458df96fd56830fdb35397e95a80274761ecff5
2010-09-15 17:40:14 -07:00
d7693c4c8e resolved conflicts for merge of 76445f3a to master
Change-Id: I658894dcaddbf0de428e3c51dbcdc306d3f47a52
2010-09-15 17:03:51 -07:00
6b1ff61f62 am 858f0a76: am 8e5e4dad: close update package before installing; allow remount
Merge commit '858f0a763d0f736eb721f54257b6164886bfcbfc'

* commit '858f0a763d0f736eb721f54257b6164886bfcbfc':
  close update package before installing; allow remount
2010-09-15 16:32:52 -07:00
4f69afdb63 am bd4bc088: am d12560aa: add the ability to seek to a raw location while reading MTD partition
Merge commit 'bd4bc088e286b87a5d1469598644125ecc0fd547'

* commit 'bd4bc088e286b87a5d1469598644125ecc0fd547':
  add the ability to seek to a raw location while reading MTD partition
2010-09-15 12:32:22 -07:00
85bcf776e1 am 8a8e6cc3: (cherry-pick) EMMC support in applypatch
Merge commit '8a8e6cc33cc0dcfe7e184b59d5ef1f1c29095509' into gingerbread-plus-aosp

* commit '8a8e6cc33cc0dcfe7e184b59d5ef1f1c29095509':
  (cherry-pick) EMMC support in applypatch
2010-09-15 11:17:34 -07:00
9f89b0e467 am 56c5105b: support for ext4/EMMC filesystems in updater binary
Merge commit '56c5105bd7096704eaed35329b2c8c84cc282867' into gingerbread-plus-aosp

* commit '56c5105bd7096704eaed35329b2c8c84cc282867':
  support for ext4/EMMC filesystems in updater binary
2010-09-15 11:14:51 -07:00
76445f3aef am 8674a726: (cherry-pick) support installing any .zip file on the sdcard
Merge commit '8674a726ff05a4a6c09c6934778c251635f130a8' into gingerbread-plus-aosp

* commit '8674a726ff05a4a6c09c6934778c251635f130a8':
  (cherry-pick) support installing any .zip file on the sdcard
2010-09-15 11:12:34 -07:00
8a8e6cc33c (cherry-pick) EMMC support in applypatch
Let applypatch read and write EMMC partitions as well as MTD ones.
This enables incremental updates that include boot image changes, as
well as OTA of new recovery partitions.

Change-Id: Ib1861219c7ca66dff29ad02d6a0a14e5f03eb4d8
2010-09-15 11:12:11 -07:00
56c5105bd7 support for ext4/EMMC filesystems in updater binary
Make the mount and format functions take extra parameters describing
the filesystem type and add support for mounting and formatting ext4
filesystems on EMMC.

Change recovery to consistently use stdout for status messages instead
of mixing stdout and stderr.
2010-09-15 11:10:02 -07:00
8674a726ff (cherry-pick) support installing any .zip file on the sdcard
Replaces the "install sdcard:update zip" menu option with one that
displays a menu of zip files (and subdirs) on the sdcard and lets you
pick which one to install.

Change-Id: Icff541525f2fdfc8939a91af626ecc386ac9dd07
2010-09-15 11:08:23 -07:00
858f0a763d am 8e5e4dad: close update package before installing; allow remount
Merge commit '8e5e4dada713609c9b2c45ea9cf4572bb89ef761' into gingerbread-plus-aosp

* commit '8e5e4dada713609c9b2c45ea9cf4572bb89ef761':
  close update package before installing; allow remount
2010-09-14 21:32:14 -07:00
8e5e4dada7 close update package before installing; allow remount
Close the update package before invoking the binary, to allow the
installer to unmount /cache if it wants to.  Add a function to allow
remounting of a mount as read-only.

Change-Id: Idfcc96c3da66083295177f729263560be58034e4
2010-09-14 21:26:38 -07:00
bd4bc088e2 am d12560aa: add the ability to seek to a raw location while reading MTD partition
Merge commit 'd12560aa2134d3af21a1220cd4873553f9c51743' into gingerbread-plus-aosp

* commit 'd12560aa2134d3af21a1220cd4873553f9c51743':
  add the ability to seek to a raw location while reading MTD partition
2010-09-14 15:32:07 -07:00
d12560aa21 add the ability to seek to a raw location while reading MTD partition
Change-Id: Id1563ca667c50e61cf1bb15d2cf783a50937eece
2010-09-14 15:28:54 -07:00
4e10b135cc Lie and say it is version 2 for backwards compatibility.
Change-Id: I5b0627fd49d3ee9f562c67bcac48783b00198ab0
2010-09-13 15:14:07 -07:00
56c1b3b576 add support for bml dumping
Change-Id: I9dd7fd8552d4efce533c23541f3612c01e3bd90b
2010-09-13 15:08:49 -07:00
68df48c28f implement redbend flashing
Change-Id: Icad93103ed2321ad8b6aecbbf2e0f2f8fe139c0f
2010-09-13 15:04:54 -07:00
28a41b4df2 initial support for bml backup and restore
Change-Id: I7e6f1a76371c0d1c1f4cfac0413ba6fa7743f17a
2010-09-13 14:55:17 -07:00
5a9fe1c964 missing
Change-Id: I836d8c28c9efce034032fa3bd2e0e15cac1ad23f
2010-09-13 14:33:50 -07:00
b5a36a0e20 add bmlutils
Change-Id: Ia402c4fcd2881cfb7cf7318718933ed64a19ec6b
2010-09-13 14:33:15 -07:00
e5678e9249 initial support for flashing samsung kernels via redbend_ua
Change-Id: I9033146899d596c6d0a4ba8a5fad080d799d96ae
2010-09-13 13:25:11 -07:00
6a84721c76 am f94a3575: am 61ba7a83: stop treating all-zero blocks as bad
Merge commit 'f94a3575d76f1fd6df20f82ca28fff688d53cfbc'

* commit 'f94a3575d76f1fd6df20f82ca28fff688d53cfbc':
  stop treating all-zero blocks as bad
2010-09-12 14:28:45 -07:00
f94a3575d7 am 61ba7a83: stop treating all-zero blocks as bad
Merge commit '61ba7a83ef46494689801ddaad569d7d174153b1' into gingerbread-plus-aosp

* commit '61ba7a83ef46494689801ddaad569d7d174153b1':
  stop treating all-zero blocks as bad
2010-09-12 14:23:25 -07:00
61ba7a83ef stop treating all-zero blocks as bad
Change-Id: If49fa6485f66598d16a7e44fce3129de55fab422
2010-09-12 13:36:40 -07:00
0b519b25c3 am a2c9a1e8: am aaf3f56c: block is bad if ioctl() returns nonzero
Merge commit 'a2c9a1e8a2b99bd8197c83b2f749ec61bc0312f8'

* commit 'a2c9a1e8a2b99bd8197c83b2f749ec61bc0312f8':
  block is bad if ioctl() returns nonzero
2010-09-09 17:01:49 -07:00
a2c9a1e8a2 am aaf3f56c: block is bad if ioctl() returns nonzero
Merge commit 'aaf3f56c44c37dca4ef9cc9efde68727ca26105f' into gingerbread-plus-aosp

* commit 'aaf3f56c44c37dca4ef9cc9efde68727ca26105f':
  block is bad if ioctl() returns nonzero
2010-09-09 16:59:05 -07:00
aaf3f56c44 block is bad if ioctl() returns nonzero
Change-Id: I6fc4ce796bc663d05035927c0af0ce7ab6d07218
2010-09-09 16:54:35 -07:00
4233c7fb3c Use the primary device.
Change-Id: Id45fcedcb5b3cacd753346a117423a462a00efb2
2010-09-03 22:16:57 -07:00
b56db27d08 am 28cae98c: am 4bc98062: add --show_text option to recovery
Merge commit '28cae98c834fb4bc47588b34dc3fe19811d5162b'

* commit '28cae98c834fb4bc47588b34dc3fe19811d5162b':
  add --show_text option to recovery
2010-09-03 11:23:21 -07:00
28cae98c83 am 4bc98062: add --show_text option to recovery
Merge commit '4bc980626c1cf6f1ea7d36e4b54e0023c896c9de' into gingerbread-plus-aosp

* commit '4bc980626c1cf6f1ea7d36e4b54e0023c896c9de':
  add --show_text option to recovery
2010-09-03 11:20:50 -07:00
4bc980626c add --show_text option to recovery
Change-Id: Ie6c6c920260dfa759fbb15b1f352d6bb0fa7146c
2010-09-03 11:18:36 -07:00
5200114fe8 am 4c7c2f73: (-s ours) am 532c8600: Revert 21f0f97eba
Merge commit '4c7c2f73af773872faf5a65167d74900865d96ba'

* commit '4c7c2f73af773872faf5a65167d74900865d96ba':
  Revert 21f0f97eba
2010-09-01 17:03:23 -07:00
3e115b81a4 am 17b44ee3: (-s ours) am 21f0f97e: Fix for crespo.
Merge commit '17b44ee3d82d7b8efa8dc3bc17d78fee11d72e01'

* commit '17b44ee3d82d7b8efa8dc3bc17d78fee11d72e01':
  Fix for crespo.
2010-09-01 17:01:06 -07:00
4c7c2f73af am 532c8600: Revert 21f0f97eba
Merge commit '532c86002bb89db43094b27ec50f001ae173c650' into gingerbread-plus-aosp

* commit '532c86002bb89db43094b27ec50f001ae173c650':
  Revert 21f0f97eba
2010-09-01 14:56:27 -07:00
17b44ee3d8 am 21f0f97e: Fix for crespo.
Merge commit '21f0f97ebabb47adcbfe8d38b02685f2019b4eb3' into gingerbread-plus-aosp

* commit '21f0f97ebabb47adcbfe8d38b02685f2019b4eb3':
  Fix for crespo.
2010-09-01 14:53:32 -07:00
532c86002b Revert 21f0f97eba
Change-Id: I46e4d7fe76e4219207e46f19e50188e38bb932b7
2010-09-01 14:52:22 -07:00
21f0f97eba Fix for crespo.
Change-Id: I008510bf614606a46a630c7adc39464ce1143ec3
2010-08-30 17:26:53 -07:00
91e9e830e2 new fix permissions 2010-08-26 10:41:08 -07:00
fad25ab75b merge with eclair recovery 2010-08-26 10:40:57 -07:00
37d58711f6 am 97900287: am 965f9dc4: merge -s ours from froyo-release so that upgrading to gingerbread is a git fast-forward
Merge commit '979002871ddc417dfdfb6a6542b9018626af7883'

* commit '979002871ddc417dfdfb6a6542b9018626af7883':
  fix bug in applying patches
  remove shadowed variable declaration
2010-08-24 11:54:52 -07:00
979002871d am 965f9dc4: merge -s ours from froyo-release so that upgrading to gingerbread is a git fast-forward
Merge commit '965f9dc45345486e885b59b4776f0ca5e765ec20' into gingerbread-plus-aosp

* commit '965f9dc45345486e885b59b4776f0ca5e765ec20':
  fix bug in applying patches
  remove shadowed variable declaration
2010-08-23 19:10:18 -07:00
965f9dc453 merge -s ours from froyo-release so that upgrading to gingerbread is a git fast-forward
Change-Id: I4d56dc0235f3df1306736c42144dccb26b876b74
2010-08-23 19:07:40 -07:00
baf6e35473 am c080bc54: am fbd7ae7a: am 201cd466: remove shadowed variable declaration
Merge commit 'c080bc549aaf272c77fe7903e52c2a2c0d8de1bb'

* commit 'c080bc549aaf272c77fe7903e52c2a2c0d8de1bb':
  remove shadowed variable declaration
2010-08-16 07:44:51 -07:00
8101125ee5 Changes to work with updated make_ext4fs tool that supports creating sparse images.
An extra parameter was added to the make_ext4fs() function, we these tools need
to be updated to match.

Change-Id: Id640a7f2b03153eb333b00337f0f991ff5332349
2010-08-13 19:22:47 -07:00
dff87121ad fix bug in applying patches
When restarting a patch from crashing in the middle of a large file,
we're not finding the correct patch to apply to the copy saved in
cache.

Change-Id: I41cb2b87d096bb7a28a10c4cf3902facd45d4c9d
2010-08-13 11:50:54 -07:00
beecac49da remove shadowed variable declaration
An accidental variable declaration ("int enough_space = ..." instead
of "enough_space = " inside a block) shadowing the real one meant we
were always using the copy-to-cache path for patching, even when not
necessary.  Remove it.  Enforce an absolute minimum of free space as
well, to avoid running into problems patching small files, now that
the copy-to-cache path is (inadvertently) well-tested.

Change-Id: Idb7d57241a9adcda2e11001fa44f0cd67ce40d19
2010-08-13 11:47:56 -07:00
c080bc549a am fbd7ae7a: am 201cd466: remove shadowed variable declaration
Merge commit 'fbd7ae7a1ce0060221241ed02c576983c1f48d34' into gingerbread-plus-aosp

* commit 'fbd7ae7a1ce0060221241ed02c576983c1f48d34':
  remove shadowed variable declaration
2010-08-13 10:02:51 -07:00
fbd7ae7a1c am 201cd466: remove shadowed variable declaration
Merge commit '201cd46680f5789e21a57fb4476ab0ba0c0ed4c0' into gingerbread

* commit '201cd46680f5789e21a57fb4476ab0ba0c0ed4c0':
  remove shadowed variable declaration
2010-08-13 09:59:52 -07:00
201cd46680 remove shadowed variable declaration
An accidental variable declaration ("int enough_space = ..." instead
of "enough_space = " inside a block) shadowing the real one meant we
were always using the copy-to-cache path for patching, even when not
necessary.  Remove it.  Enforce an absolute minimum of free space as
well, to avoid running into problems patching small files, now that
the copy-to-cache path is (inadvertently) well-tested.

Change-Id: Idb7d57241a9adcda2e11001fa44f0cd67ce40d19
2010-08-13 09:41:21 -07:00
80dcee145f am c4e32005: am 17986e6b: am 8cd9e4f3: fix bug in applying patches
Merge commit 'c4e3200578ad670bee9f5a88e90e7a77089d5df7'

* commit 'c4e3200578ad670bee9f5a88e90e7a77089d5df7':
  fix bug in applying patches
2010-08-12 17:57:45 -07:00
c4e3200578 am 17986e6b: am 8cd9e4f3: fix bug in applying patches
Merge commit '17986e6b8766ef9bdaa49efc7099e3867ca1978a' into gingerbread-plus-aosp

* commit '17986e6b8766ef9bdaa49efc7099e3867ca1978a':
  fix bug in applying patches
2010-08-12 17:55:24 -07:00
17986e6b87 am 8cd9e4f3: fix bug in applying patches
Merge commit '8cd9e4f3d4eba481b411482331293c8079ab24b2' into gingerbread

* commit '8cd9e4f3d4eba481b411482331293c8079ab24b2':
  fix bug in applying patches
2010-08-12 17:52:34 -07:00
8cd9e4f3d4 fix bug in applying patches
When restarting a patch from crashing in the middle of a large file,
we're not finding the correct patch to apply to the copy saved in
cache.

Change-Id: I41cb2b87d096bb7a28a10c4cf3902facd45d4c9d
2010-08-12 17:38:09 -07:00
04611da55b support using an EMMC misc partition to store recovery arguments
Change-Id: I9f912857cfc6afb8ba764f5541af7f01df029a77
2010-08-12 15:35:29 -07:00
db314d69f0 Working ASLR implementation
Separate files for retouch functionality are in minelf/*

ASLR for shared libraries is controlled by "-a" in ota_from_target_files.
Binary files are self-contained. Retouch logic can recover from crashes.

Signed-off-by: Hristo Bojinov <hristo@google.com>
Change-Id: I76c596abf4febd68c14f9d807ac62e8751e0b1bd
2010-08-02 14:17:33 -07:00
f635d2e910 don't go into file select menu when mounting external storage fails
Change-Id: If0efeddc28e1dbb52d9e52abf53323e2cc97c8f0
2010-08-02 11:34:46 -07:00
dc9e87c44b generalize "install from sdcard" to "install from external storage"
Allow sideloading of OTA packages from USB drives that appear as
/dev/block/sda1.

Change-Id: I1908576c24547cd0088475d8c8917699cd906868
2010-07-29 17:08:50 -07:00
b4277c25c6 Mute unwanted error message
This CL removes the following line from the top of build logs:
"diff: out/target/product/*/obj/PACKAGING/updater_extensions_intermediates/register.inc.list: No such file or directory"

Change-Id: I79c15a69a0b1b0da0e45620b45a7a0fea5625250
2010-07-20 17:31:04 -07:00
ef83d3ea87 fix
Change-Id: I9bc8cfde27b89d9a548c47c5727530c604d36ee0
2010-07-19 08:54:23 -07:00
702294d5b8 merge
Change-Id: I25a675887320afd2984523efbc3b7506231ebe4b
2010-07-19 08:43:05 -07:00
f146bc1b74 removal of the recovery checkpoint needs to happen AFTER sdcard is mounted. 2010-07-19 08:41:40 -07:00
d61e56ab36 version 2.5.0.0 2010-07-19 08:41:40 -07:00
9565424508 add confirmations to anything that would change the system. 2010-07-19 08:41:40 -07:00
17bba907ac Make generic confirmation function. 2010-07-19 08:40:58 -07:00
4ca9b4c3a0 allow toggling of software back menu item. add recovery checkpoint file. mount auto now uses busybox mount. 2010-07-19 08:40:58 -07:00
efa6530dbd up the version 2010-07-19 08:40:58 -07:00
b41b4589c2 2.0.2.0 2010-07-19 08:40:58 -07:00
fdda0d66d3 fail 2010-07-19 08:40:57 -07:00
30e5b7f6dc change where the recovery version is spit 2010-07-19 08:40:57 -07:00
6e5851647a command line nandroid 2010-07-19 08:40:57 -07:00
050d0f7fec resolved conflicts for merge of c02c37a1 to master
Change-Id: Iafb9cb4adf27a7086d587d95e94ab1bd050099dc
2010-07-09 09:13:51 -07:00
c02c37a1e6 am 23ceeea8: make a copy of sideloaded packages in /tmp before verifying
Merge commit '23ceeea85e6a3555dd3d7140128e310954cadf7f' into gingerbread-plus-aosp

* commit '23ceeea85e6a3555dd3d7140128e310954cadf7f':
  make a copy of sideloaded packages in /tmp before verifying
2010-07-08 17:50:26 -07:00
23ceeea85e make a copy of sideloaded packages in /tmp before verifying
Copy a sideloaded package into /tmp, then verify and install the copy,
to prevent malicious users from overwriting the package between
verification and install.

Bug: 2826890 package can be replaced during verification
Bug: 2058160 Recovery should copy sideloaded (sd card) update ...
Change-Id: I3de148b0f1a671f1974782b6855527caeaefda23
2010-07-08 17:27:55 -07:00
f291d858f8 EMMC support in applypatch
Let applypatch read and write EMMC partitions as well as MTD ones.
This enables incremental updates that include boot image changes, as
well as OTA of new recovery partitions.

Change-Id: I3766b9e77c639769ddf693b675da51d57f6e6b1d
2010-07-07 15:18:27 -07:00
82c2ca262e Backup of Froyo apps on external storage. 2010-07-03 13:57:28 -07:00
d3cc60b036 nandroid executable
Change-Id: I697530a804be443260059b24e231d77dfe5bc6c4
2010-07-03 13:56:45 -07:00
3d177d055c support for ext4/EMMC filesystems in updater binary
Make the mount and format functions take extra parameters describing
the filesystem type and add support for mounting and formatting ext4
filesystems on EMMC.

Change recovery to consistently use stdout for status messages instead
of mixing stdout and stderr.
2010-07-01 15:42:28 -07:00
b442b45bdd Merge "support userdata and cache partitions using emmc/ext4 instead of mtd/yaffs" 2010-07-01 09:21:12 -07:00
d823d5f327 fix build
Change-Id: I284e852856ffa7f6588b243a628c35e5f6d73fc7
2010-07-01 08:21:02 -07:00
789ab6bed2 alphabetical sort
Change-Id: I4b1bb6787a5cbe1e99e3d8b0cc5bf37d7167398d
2010-07-01 00:23:25 -07:00
916f5538f9 fail
Change-Id: I93fc7a7a717e5a7eceafd7175e22c32b2588742a
2010-06-30 23:31:35 -07:00
f2954b5b64 Always use the default recovery ui.
Change-Id: Ia73aeb932498d39e508bf232c0070910aa204ec5
2010-06-30 23:27:26 -07:00
107629b02d forward port excluded bootloader stuff from eclair
Change-Id: I03fb0d4dc982a3718a616c6204e70a3e11cff8f8
2010-06-30 23:17:53 -07:00
42cfc2cc05 am 60faafcf: merge from open-source master
Merge commit '60faafcf01ff7f4179cdcaefd24b10ac4ee7f692'

* commit '60faafcf01ff7f4179cdcaefd24b10ac4ee7f692':
2010-06-30 15:54:38 -07:00
60faafcf01 merge from open-source master
Change-Id: I9d0122dbf1a9c2bd1898c41766c5bf4320f2313a
2010-06-30 15:51:09 -07:00
49c73a76a3 support userdata and cache partitions using emmc/ext4 instead of mtd/yaffs
Change-Id: I827af624c9ec7c64decb702de8c0310cf19b4141
2010-06-29 17:36:28 -07:00
ba634dc9f7 am c78a9698: am ecc76ba5: Set adbd to be disabled by default in recovery
Merge commit 'c78a9698dd55a165c2206c380f87f173bacba2aa'

* commit 'c78a9698dd55a165c2206c380f87f173bacba2aa':
  Set adbd to be disabled by default in recovery
2010-06-28 12:28:45 -07:00
4fef81a5a9 am ecc76ba5: Set adbd to be disabled by default in recovery
Merge commit 'ecc76ba5516d62a886f9c290906e0ca50702c9ab' into froyo-plus-aosp

* commit 'ecc76ba5516d62a886f9c290906e0ca50702c9ab':
  Set adbd to be disabled by default in recovery
2010-06-28 12:24:46 -07:00
c78a9698dd am ecc76ba5: Set adbd to be disabled by default in recovery
Merge commit 'ecc76ba5516d62a886f9c290906e0ca50702c9ab' into gingerbread

* commit 'ecc76ba5516d62a886f9c290906e0ca50702c9ab':
  Set adbd to be disabled by default in recovery
2010-06-28 12:24:16 -07:00
ecc76ba551 Set adbd to be disabled by default in recovery
Change-Id: I74fa6edc4b001247b20be52e8301d18407fede2c
2010-06-28 09:01:22 -07:00
9e6513f145 am 21b97ed5: Add __attribute__((format(printf, a, b))) to printf like functions.
Merge commit '21b97ed5693d039e8b9dea57a160d3307f412682'

* commit '21b97ed5693d039e8b9dea57a160d3307f412682':
  Add __attribute__((format(printf, a, b))) to printf like functions.
2010-06-24 17:16:49 -07:00
21b97ed569 Add __attribute__((format(printf, a, b))) to printf like functions.
Fix potential string format bug.

Change-Id: Ie05aac53b2c45a48bd68e340b76ccb21edfd28b7
2010-06-24 16:11:17 -07:00
0eb14b30e0 Merge from Froyo. 2010-06-23 17:38:05 -07:00
b3d9a15b66 am dd6a0412: recovery: Add ueventd service 2010-05-14 14:35:50 -07:00
dd6a0412b5 recovery: Add ueventd service
Change-Id: Iad448bc1608f88c5db2108475f35b88ea2877b07
2010-05-14 13:44:13 -07:00
eb681fd491 am be42930f: am 97ca48e7: generic_x86 support 2010-05-03 16:17:50 -07:00
be42930f0b am 97ca48e7: generic_x86 support
Merge commit '97ca48e7f4ac8d3842f74f92b8f40d0e74733f38' into kraken

* commit '97ca48e7f4ac8d3842f74f92b8f40d0e74733f38':
  generic_x86 support
2010-05-03 16:14:51 -07:00
97ca48e7f4 generic_x86 support
Add in Makefiles and support files for x86 builds
  Based on changes by: wonjong.lee <wonjong.lee@windriver.com>
  Additional changes by: Mark Gross <mark.gross@intel.com>
  Additional changes by: Bruce Beare <brucex.j.beare@intel.com>

Change-Id: I71fcf58f116e4e9047e7d03fdb28e3308553ce5c
2010-05-03 15:58:50 -07:00
be598881d0 support installing any .zip file on the sdcard
Replaces the "install sdcard:update zip" menu option with one that
displays a menu of zip files (and subdirs) on the sdcard and lets you
pick which one to install.

Change-Id: I85c94c0e9bc8e05ca52031fc29ca2624c2695ced
2010-04-08 14:36:55 -07:00
6102227b0b am 52219a68: (-s ours) DO NOT MERGE Encrypted File Systems integration. Recovery changes. 2010-04-01 17:42:37 -07:00
52219a68a8 DO NOT MERGE
Encrypted File Systems integration. Recovery changes.

Change-Id: I932f73a6f937aac061128e1134eab08c30f0471d
2010-04-01 17:14:57 -07:00
f33e24645b Merge "Encrypted File Systems part 3. Recovery changes." 2010-03-31 10:06:27 -07:00
be17b1c0d7 am 51282faa: (-s ours) am 2654f5aa: (-s ours) DO NOT MERGE Removing unused recovey options. Please refer to Bug#2502219 for more info. 2010-03-29 16:31:06 -07:00
51282faa8c am 2654f5aa: (-s ours) DO NOT MERGE Removing unused recovey options. Please refer to Bug#2502219 for more info.
Merge commit '2654f5aae18c67ad9aff6dbcdf9bc67b62e37d2d' into kraken

* commit '2654f5aae18c67ad9aff6dbcdf9bc67b62e37d2d':
  DO NOT MERGE
2010-03-29 16:19:49 -07:00
2654f5aae1 DO NOT MERGE
Removing unused recovey options.
Please refer to Bug#2502219 for more info.

Change-Id: I2fe3cdb0c8b93ed7e1cc4093824fbe181f5f0aea
2010-03-26 16:03:44 -07:00
31f6ee88ce Encrypted File Systems part 3. Recovery changes.
Change-Id: I932f73a6f937aac061128e1134eab08c30f0471d
2010-03-15 09:45:49 -07:00
dcc38b3c15 Add an empty CleanSpec.mk
Change-Id: Icd177bd26120e0c8929faa8d1007f6c5bd446cb8
2010-03-08 18:04:03 -08:00
5b695f393e make StringValue wrapper okay to call on NULL
The docs say "don't do this", but it's trivial to make safe.  Make
StringValue(NULL) return NULL instead of crashing.

Change-Id: I2221bcb4c98d8adb4e25c764d7bdcfa787822bcf
2010-02-24 15:05:07 -08:00
c4351c7910 refactor applypatch and friends
Change the applypatch function to take meaningful arguments instead of
argc and argv.  Move all the parsing of arguments into main.c (for the
standalone binary) and into install.c (for the updater function).
applypatch() takes patches as Value objects, so we can pass in blobs
extracted from the package without ever writing them to temp files.

The patching code is changed to read the patch from memory instead of
a file.

A bunch of compiler warnings (mostly about signed vs unsigned types)
are fixed.

Support for the IMGDIFF1 format is dropped.  (We've been generating
IMGDIFF2 packages for some time now.)

Change-Id: I217563c500012750f27110db821928a06211323f
2010-02-22 15:30:33 -08:00
583fc12c3d add missing includes to fix mac build (maybe)
Change-Id: Id2712940c4929f3a8b3ba5d4e9e03bb8034747ee
2010-02-19 16:07:57 -08:00
512536a54a relocate applypatch; add type system and new functions to edify
- Move applypatch to this package (from build).

- Add a rudimentary type system to edify:  instead of just returning a
  char*, functions now return a Value*, which is a struct that can
  carry different types of value (currently just STRING and BLOB).
  Convert all functions to this new scheme.

- Change the one-argument form of package_extract_file to return a
  Value of the new BLOB type.

- Add read_file() to load a local file and return a blob, and
  sha1_check() to test a blob (or string) against a set of possible
  sha1s.  read_file() uses the file-loading code from applypatch so it
  can read MTD partitions as well.

This is the start of better integration between applypatch and the
rest of edify.

b/2361316 - VZW Issue PP628: Continuous reset to Droid logo:
            framework-res.apk update failed (CR LIBtt59130)

Change-Id: Ibd038074749a4d515de1f115c498c6c589ee91e5
2010-02-18 14:22:12 -08:00
21854ccdb2 Filename check and free allocated strings
Make sure file is valid before we try to read it. Also free all the
strings we allocate in various functions so we don't leak memory.

Change-Id: Ica3c8dae992e73718c79c12ff5d7e315c290caea
2010-02-17 18:33:44 -08:00
2e068dc330 am da846fcf: am 4c382b13: reconcile main tree with open-source eclair
Merge commit 'da846fcf1b6a7bbd2f9f30c965b25f084568ef75'

* commit 'da846fcf1b6a7bbd2f9f30c965b25f084568ef75':
  android-2.1_r1 snapshot
2010-02-05 14:09:04 -08:00
da846fcf1b am 4c382b13: reconcile main tree with open-source eclair
Merge commit '4c382b13657be5d949e7dfc9ef46a66f2eb496e0' into eclair-plus-aosp

* commit '4c382b13657be5d949e7dfc9ef46a66f2eb496e0':
  android-2.1_r1 snapshot
2010-02-05 08:22:49 -08:00
4c382b1365 reconcile main tree with open-source eclair 2010-02-05 08:09:31 -08:00
e08991e02a bump updater API version to 3; deprecate firmware update command
Remove support for the HTC-specific "firmware" update command and the
corresponding edify function write_firmware_update().  This
functionality is now done by an edify extension library that lives in
vendor/htc.

Change-Id: I80858951ff10ed8dfff98aefb796bef009e05efb
2010-02-03 09:20:07 -08:00
93dbe07ff6 Merge "change log recovery to generic device_recovery_start function" 2010-02-02 08:54:10 -08:00
efa1bab94c change log recovery to generic device_recovery_start function
Remove (or at least stop calling) the HTC-specific mechanism for
preserving the recovery log from before a radio or hboot update.
Replace it with a generic device_recovery_start() function which each
device's code can implement to do whatever it wants on recovery
startup.

Change-Id: If3cca4b498c0b1cf0565236404ecf56a1fc46123
2010-02-01 15:59:12 -08:00
6aece33b3f add a one-argument version of package_extract_file
Add a version of package_extract_file that returns the file data as
its return value (to be consumed by some other edify function that
expects to receive a bunch of binary data as an argument).  Lets us
avoid having two copies of a big file in memory (extracting it into
/tmp, which is a ramdisk, and then having something load it into
memory) when doing things like radio updates.

Change-Id: Ie26ece5fbae457eb0ddcd8a13d74d78a769fbc70
2010-02-01 14:40:12 -08:00
b551724ceb reconcile android-2.1_r1 snapshot 2010-01-29 14:07:31 -08:00
aa062531aa fix parsing of dumpkeys output
%i can't be used to read unsigned ints (though it happens to work with
bionic).  Change to %x and %u as appropriate.

Change-Id: I8ea9ca16a939501757cf70fc5953abee26c8231c
http://b/2402231 - Parser for /res/keys interprets n0inv as a signed int
2010-01-28 16:51:00 -08:00
687bc12ccf save the recovery log from before HTC firmware updates
When doing a firmware (radio or hboot) update on HTC devices, save the
recovery log in block 1 of the cache partition, before the firmware
image and the UI bitmaps.  When we boot back into recovery after the
firmware update to reformat the cache partition, copy that log out of
cache before reformatting it and dump it into the current invocation's
log.

The practical upshot of all this is that we can see the log output
from radio and hboot updates.

Change-Id: Ie0e89566754c88f4bed6a90d8a0aa04047b01a27
2010-01-21 12:50:04 -08:00
883b4c8be5 am 4e9332cb: am 22d79a5c: make offsets in firmware update header not point to bad blocks
Merge commit '4e9332cb0bb84df4c08bbb469e59a54eab2a9df0'

* commit '4e9332cb0bb84df4c08bbb469e59a54eab2a9df0':
  make offsets in firmware update header not point to bad blocks
2010-01-13 12:17:11 -08:00
4e9332cb0b am 22d79a5c: make offsets in firmware update header not point to bad blocks
Merge commit '22d79a5c5eab9c1e86ff2af210bb072689e2d630' into eclair-plus-aosp

* commit '22d79a5c5eab9c1e86ff2af210bb072689e2d630':
  make offsets in firmware update header not point to bad blocks
2010-01-13 11:24:42 -08:00
4c5f9f3416 make offsets in firmware update header not point to bad blocks
hboot will apparently fail to install if the first block of the image
(the one pointed to by the offset in the block 0 header) is a bad
block.  (Hopefully it handles subsequent bad blocks.)

This change makes the MTD write code keep track of the bad blocks it
has skipped over, so that the offset in the header can be adjusted to
be the address of the first successfully written block.

Change-Id: I45d58e32a36d0c1dbc0a7f871bd5985b6c8ff524
http://b/2358012 - passion: failure to flash hboot (bad blocks?)
2010-01-13 09:21:25 -08:00
b765729081 android-2.1_r1 snapshot 2010-01-12 15:18:06 -08:00
be47155f75 am 158657bc: merge from open-source master
Merge commit '158657bc5ce438d3cf1f601255896b854fd49103'

* commit '158657bc5ce438d3cf1f601255896b854fd49103':
  Security: Fix typo in recovery EOCD detection.
2009-12-21 15:47:17 -08:00
158657bc5c merge from open-source master 2009-12-21 15:31:49 -08:00
9b514530a6 am d36308c2: am 17a47098: use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
Merge commit 'd36308c26d3f2947f4ff49f2ecc22cbb659fdf37'

* commit 'd36308c26d3f2947f4ff49f2ecc22cbb659fdf37':
  use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
2009-12-15 15:04:32 -08:00
d36308c26d am 17a47098: use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
Merge commit '17a47098d2a4214397f8b30e2692c9487d7ab5ff' into eclair-plus-aosp

* commit '17a47098d2a4214397f8b30e2692c9487d7ab5ff':
  use MEMGETBADBLOCK to look for bad blocks when reading MTD partitions
2009-12-15 07:42:36 -08:00
8fae8279fa Merge commit 'goog/eclair-plus-aosp' 2009-12-15 00:44:04 -08:00
25215285c4 am 9b430e11: am 73ae31ce: add a simple unit test for the OTA package verifier
Merge commit '9b430e11d6c4fb907d0aa96667142e2c00585e09'

* commit '9b430e11d6c4fb907d0aa96667142e2c00585e09':
  add a simple unit test for the OTA package verifier
2009-12-10 15:52:09 -08:00
9b430e11d6 am 73ae31ce: add a simple unit test for the OTA package verifier
Merge commit '73ae31ce0ac09c0e45924d817644261c87ab1a60' into eclair-mr2-plus-aosp

* commit '73ae31ce0ac09c0e45924d817644261c87ab1a60':
  add a simple unit test for the OTA package verifier
2009-12-10 15:35:23 -08:00
bd6181ad58 Merge change I117fdea9
* changes:
  Recovery changes for Encrypted File Systems. This change enables/disables the Encrypted file systems feature. It reads some properties form the data partition, wipes the partition out, and then rewrites the proper properties again into the data partition to signal that encrypted FS are enabled.
2009-12-10 14:51:10 -08:00
0523156775 Recovery changes for Encrypted File Systems.
This change enables/disables the Encrypted file systems feature. It reads some properties form the data partition, wipes the partition out, and then rewrites the proper properties again into the data partition to signal that encrypted FS are enabled.
2009-12-10 14:49:04 -08:00
002c9dfb80 am 2278a04a: am 9acf28a3: am c652e41d: fix cut-and-paste error in verifier
Merge commit '2278a04a0921007d726e9e1ec4b668860f961f88'

* commit '2278a04a0921007d726e9e1ec4b668860f961f88':
  fix cut-and-paste error in verifier
2009-12-10 14:37:57 -08:00
73ae31ce0a add a simple unit test for the OTA package verifier 2009-12-09 17:01:45 -08:00
2278a04a09 am 9acf28a3: am c652e41d: fix cut-and-paste error in verifier
Merge commit '9acf28a390aab3e0f394c701bc3cda6cbc9393b3' into eclair-mr2-plus-aosp

* commit '9acf28a390aab3e0f394c701bc3cda6cbc9393b3':
  fix cut-and-paste error in verifier
2009-12-09 15:54:14 -08:00
3b0f484776 Security: Fix typo in recovery EOCD detection.
This issue results in the ability to modify the contents of a signed
OTA recovery image.
2009-12-09 01:31:06 -05:00
9acf28a390 am c652e41d: fix cut-and-paste error in verifier
Merge commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12' into eclair-mr2

* commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12':
  fix cut-and-paste error in verifier
2009-12-08 15:54:50 -08:00
6149073651 am c652e41d: fix cut-and-paste error in verifier
Merge commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12' into eclair-plus-aosp

* commit 'c652e41d9173e299a8e1805ae1b2bba75a34ae12':
  fix cut-and-paste error in verifier
2009-12-08 15:54:32 -08:00
b8f506fb37 am 6e5be9b2: merge from open-source master
Merge commit '6e5be9b24c232be4cfc22b7cbabb0fdf6d869f7c'

* commit '6e5be9b24c232be4cfc22b7cbabb0fdf6d869f7c':
  eclair snapshot
2009-11-15 15:00:59 -08:00
6e5be9b24c merge from open-source master 2009-11-15 14:55:00 -08:00
052acd61c8 merge from open-source master
Merge commit 'goog/stage-korg-master' into HEAD
2009-11-15 14:05:55 -08:00
b2ce982d43 merge from eclair 2009-11-15 12:05:33 -08:00
a43c44f31f eclair snapshot 2009-11-12 18:45:15 -08:00
f88cea6ded am 4011770f: merge from open-source master
Merge commit '4011770f2d06fcb743abc91a01a531c7ae2d9175'

* commit '4011770f2d06fcb743abc91a01a531c7ae2d9175':
2009-10-14 16:11:42 -07:00
4011770f2d merge from open-source master 2009-10-14 16:02:08 -07:00
31f0fc2235 am d93a2545: simplify construction of the recovery progress bar
Merge commit 'd93a25459cdefba940f254b4c5f54fd7d9cdaf11'

* commit 'd93a25459cdefba940f254b4c5f54fd7d9cdaf11':
  simplify construction of the recovery progress bar
2009-10-13 11:59:45 -07:00
2ec8a1929f am 54ec81fe: Merge change I1c8ca2e4 into eclair
Merge commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa'

* commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa':
  replace generic recovery icons
2009-10-12 12:40:12 -07:00
022229c47e am 988500b6: add terminator to recovery\'s getopt_long options array
Merge commit '988500b615de24455e1fee69e72055bb1dca9c86'

* commit '988500b615de24455e1fee69e72055bb1dca9c86':
  add terminator to recovery's getopt_long options array
2009-10-12 11:45:31 -07:00
d93a25459c simplify construction of the recovery progress bar
Instead of six separate images for the left end, right end, and tiled
center portion of the full and empty progress bars, just use two
images:  a full bar and an empty bar.  Draw the left side of the full
bar and the right side of the empty one, moving the boundary rightward
to "fill" the bar.  This makes recovery trivially smaller, and allows
fancier images to be used as progress bars.

Support paletted PNG images as resources.
2009-10-08 16:32:58 -07:00
d641a0e141 am 54ec81fe: Merge change I1c8ca2e4 into eclair
Merge commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa' into eclair-plus-aosp

* commit '54ec81fe86225d5f3ee3ab16e3266ae88cd639fa':
  replace generic recovery icons
2009-10-07 17:17:41 -07:00
42ab176195 am 988500b6: add terminator to recovery\'s getopt_long options array
Merge commit '988500b615de24455e1fee69e72055bb1dca9c86' into eclair-plus-aosp

* commit '988500b615de24455e1fee69e72055bb1dca9c86':
  add terminator to recovery's getopt_long options array
2009-10-07 11:57:04 -07:00
4526d4fe62 am 8f8bc4cb: am f93d8166: confirm before wiping user data in recovery
Merge commit '8f8bc4cb487e0f853c97cb5ff1481d707ac6b66d'

* commit '8f8bc4cb487e0f853c97cb5ff1481d707ac6b66d':
  confirm before wiping user data in recovery
2009-09-25 08:45:47 -07:00
8f8bc4cb48 am f93d8166: confirm before wiping user data in recovery
Merge commit 'f93d8166ef4c06f6ad71293ffa8a4ce469df4fa5' into eclair-plus-aosp

* commit 'f93d8166ef4c06f6ad71293ffa8a4ce469df4fa5':
  confirm before wiping user data in recovery
2009-09-22 18:28:19 -07:00
83a25d7380 am 486aa290: am fd8fb0c4: reduce fraction of progress bar for verification
Merge commit '486aa290635dbf6f60b3435694951fed3470ffdf'

* commit '486aa290635dbf6f60b3435694951fed3470ffdf':
  reduce fraction of progress bar for verification
2009-09-20 14:40:27 -07:00
486aa29063 am fd8fb0c4: reduce fraction of progress bar for verification
Merge commit 'fd8fb0c49242af5147708f1a93ea3acba546555b' into eclair-plus-aosp

* commit 'fd8fb0c49242af5147708f1a93ea3acba546555b':
  reduce fraction of progress bar for verification
2009-09-20 14:30:37 -07:00
66c76bcfcf am d16fb221: am 60babf8b: delete files before symlinking; log error messages
Merge commit 'd16fb221cd27abea8a954bd5f6554fa116366519'

* commit 'd16fb221cd27abea8a954bd5f6554fa116366519':
  delete files before symlinking; log error messages
2009-09-18 18:15:46 -07:00
d16fb221cd am 60babf8b: delete files before symlinking; log error messages
Merge commit '60babf8ba766662cc0932e8271b67daa69cddd5f' into eclair-plus-aosp

* commit '60babf8ba766662cc0932e8271b67daa69cddd5f':
  delete files before symlinking; log error messages
2009-09-18 15:49:37 -07:00
b9ad6dfd81 am 2f4fc561: am 196c25c7: don\'t complain if recovery icon is short
Merge commit '2f4fc56183f3fe2edb5e3cd5e12329871e02518f'

* commit '2f4fc56183f3fe2edb5e3cd5e12329871e02518f':
  don't complain if recovery icon is short
2009-09-17 06:38:28 -07:00
2f4fc56183 am 196c25c7: don\'t complain if recovery icon is short
Merge commit '196c25c777daedbe2fe5a45171fb42e43ceed9af' into eclair-plus-aosp

* commit '196c25c777daedbe2fe5a45171fb42e43ceed9af':
  don't complain if recovery icon is short
2009-09-15 13:46:00 -07:00
49c82ce553 am b5d542cd: am a3f89eab: add a run_program() function to edify
Merge commit 'b5d542cd40360867bc00cdb9266c0abf26448c55'

* commit 'b5d542cd40360867bc00cdb9266c0abf26448c55':
  add a run_program() function to edify
2009-09-10 14:41:05 -07:00
b5d542cd40 am a3f89eab: add a run_program() function to edify
Merge commit 'a3f89eabb7ddcf44add8ce3b321ceab6d35289cb' into eclair-plus-aosp

* commit 'a3f89eabb7ddcf44add8ce3b321ceab6d35289cb':
  add a run_program() function to edify
2009-09-10 14:30:43 -07:00
af42fa0a7d am 9a77b613: merge from open-source master
Merge commit '9a77b613f3fdf6340b0f5f24d1c725fd0001e4a9'

* commit '9a77b613f3fdf6340b0f5f24d1c725fd0001e4a9':
2009-09-04 11:05:32 -07:00
9a77b613f3 merge from open-source master 2009-09-04 07:50:41 -07:00
65a56909a3 merge from donut 2009-09-03 14:12:45 -07:00
2f39bf9a9f am cbf90380: merge from open-source master
Merge commit 'cbf903803850deb4f70490d97a1603e7b8679cc2'

* commit 'cbf903803850deb4f70490d97a1603e7b8679cc2':
  Not all failures to fopen_root_path() are serious.
2009-09-01 12:14:02 -07:00
cbf9038038 merge from open-source master 2009-09-01 08:27:43 -07:00
619ec2f3aa Not all failures to fopen_root_path() are serious.
Example: E:Can't open /cache/recovery/command.
2009-08-25 12:53:40 -07:00
6785c2534a am 34c98df7: (-s ours) do not merge: cherry-pick of c2d666bd4f from master
Merge commit '34c98df78a80881698f63ce0815f3e16823d85e0'

* commit '34c98df78a80881698f63ce0815f3e16823d85e0':
  do not merge: cherry-pick of c2d666bd4f from master
2009-08-18 12:13:35 -07:00
c2d666bd4f Recovery: When updating from SD card, update can't resume automatically
after a power loss

Submitted on behalf of Hong-Bin Wang <hong-binwang@motorola.com>
Signed-off-by: Jared Suttles <jared.suttles@motorola.com>
2009-08-17 17:39:54 -07:00
50a8a71f0b am 54e2e86c: (-s ours) do not merge: cherry-picked 60151a295c from master branch
Merge commit '54e2e86c5740a2c7a02e95e94c4aff362a5502cf'

* commit '54e2e86c5740a2c7a02e95e94c4aff362a5502cf':
  do not merge: cherry-picked 60151a295c from master branch
2009-08-17 14:11:31 -07:00
60151a295c verify whole-file signature instead of jarsigner signatures
In recovery, verify a signature that covers the entire zip file,
instead of using the jarsigner format to verify individual files.

Bug: 1328985
2009-08-14 17:26:33 -07:00
203 changed files with 12083 additions and 8358 deletions

View File

@ -1,6 +1,3 @@
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@ -8,126 +5,63 @@ commands_recovery_local_path := $(LOCAL_PATH)
# LOCAL_CPP_EXTENSION := .c
LOCAL_SRC_FILES := \
extendedcommands.c \
nandroid.c \
legacy.c \
commands.c \
recovery.c \
install.c \
roots.c \
ui.c \
verifier.c
recovery.c \
bootloader.c \
install.c \
roots.c \
ui.c \
mounts.c \
extendedcommands.c \
nandroid.c \
../../system/core/toolbox/reboot.c \
firmware.c \
edifyscripting.c \
setprop.c \
default_recovery_ui.c \
verifier.c
LOCAL_SRC_FILES += \
reboot.c \
setprop.c
ifndef BOARD_HAS_NO_MISC_PARTITION
LOCAL_SRC_FILES += \
firmware.c \
bootloader.c
else
LOCAL_CFLAGS += -DBOARD_HAS_NO_MISC_PARTITION
endif
ifdef BOARD_RECOVERY_IGNORE_BOOTABLES
LOCAL_CFLAGS += -DBOARD_RECOVERY_IGNORE_BOOTABLES
endif
ifdef BOARD_HIJACK_RECOVERY_PATH
LOCAL_CFLAGS += -DBOARD_HIJACK_RECOVERY_PATH=\"$(BOARD_HIJACK_RECOVERY_PATH)\"
endif
LOCAL_SRC_FILES += test_roots.c
ADDITIONAL_RECOVERY_FILES := $(shell echo $$ADDITIONAL_RECOVERY_FILES)
LOCAL_SRC_FILES += $(ADDITIONAL_RECOVERY_FILES)
LOCAL_MODULE := recovery
LOCAL_FORCE_STATIC_EXECUTABLE := true
RECOVERY_VERSION := ClockworkMod Recovery v2.5.1.0
ifdef I_AM_KOUSH
RECOVERY_NAME := ClockworkMod Recovery
LOCAL_CFLAGS += -DI_AM_KOUSH
else
RECOVERY_NAME := CWM-based Recovery
endif
RECOVERY_VERSION := $(RECOVERY_NAME) v5.5.0.4
LOCAL_CFLAGS += -DRECOVERY_VERSION="$(RECOVERY_VERSION)"
RECOVERY_API_VERSION := 2
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
ifeq ($(BOARD_HAS_NO_SELECT_BUTTON),true)
LOCAL_CFLAGS += -DKEY_POWER_IS_SELECT_ITEM
ifneq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),)
BOARD_RECOVERY_CHAR_WIDTH := $(shell echo $(BOARD_USE_CUSTOM_RECOVERY_FONT) | cut -d _ -f 2 | cut -d . -f 1 | cut -d x -f 1)
BOARD_RECOVERY_CHAR_HEIGHT := $(shell echo $(BOARD_USE_CUSTOM_RECOVERY_FONT) | cut -d _ -f 2 | cut -d . -f 1 | cut -d x -f 2)
else
BOARD_RECOVERY_CHAR_WIDTH := 10
BOARD_RECOVERY_CHAR_HEIGHT := 18
endif
LOCAL_CFLAGS += -DBOARD_RECOVERY_CHAR_WIDTH=$(BOARD_RECOVERY_CHAR_WIDTH) -DBOARD_RECOVERY_CHAR_HEIGHT=$(BOARD_RECOVERY_CHAR_HEIGHT)
ifdef BOARD_SDCARD_DEVICE_PRIMARY
LOCAL_CFLAGS += -DSDCARD_DEVICE_PRIMARY=\"$(BOARD_SDCARD_DEVICE_PRIMARY)\"
endif
BOARD_RECOVERY_DEFINES := BOARD_HAS_NO_SELECT_BUTTON BOARD_UMS_LUNFILE BOARD_RECOVERY_ALWAYS_WIPES BOARD_RECOVERY_HANDLES_MOUNT BOARD_TOUCH_RECOVERY
ifdef BOARD_SDCARD_DEVICE_SECONDARY
LOCAL_CFLAGS += -DSDCARD_DEVICE_SECONDARY=\"$(BOARD_SDCARD_DEVICE_SECONDARY)\"
endif
$(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
$(if $($(board_define)), \
$(eval LOCAL_CFLAGS += -D$(board_define)=\"$($(board_define))\") \
) \
)
ifdef BOARD_SDEXT_DEVICE
LOCAL_CFLAGS += -DSDEXT_DEVICE=\"$(BOARD_SDEXT_DEVICE)\"
endif
LOCAL_STATIC_LIBRARIES :=
ifdef BOARD_SDEXT_FILESYSTEM
LOCAL_CFLAGS += -DSDEXT_FILESYSTEM=\"$(BOARD_SDEXT_FILESYSTEM)\"
endif
ifdef BOARD_DATA_DEVICE
LOCAL_CFLAGS += -DDATA_DEVICE=\"$(BOARD_DATA_DEVICE)\"
endif
ifdef BOARD_DATA_FILESYSTEM
LOCAL_CFLAGS += -DDATA_FILESYSTEM=\"$(BOARD_DATA_FILESYSTEM)\"
endif
ifdef BOARD_DATADATA_DEVICE
LOCAL_CFLAGS += -DDATADATA_DEVICE=\"$(BOARD_DATADATA_DEVICE)\"
endif
ifdef BOARD_DATADATA_FILESYSTEM
LOCAL_CFLAGS += -DDATADATA_FILESYSTEM=\"$(BOARD_DATADATA_FILESYSTEM)\"
endif
ifdef BOARD_CACHE_DEVICE
LOCAL_CFLAGS += -DCACHE_DEVICE=\"$(BOARD_CACHE_DEVICE)\"
endif
ifdef BOARD_CACHE_FILESYSTEM
LOCAL_CFLAGS += -DCACHE_FILESYSTEM=\"$(BOARD_CACHE_FILESYSTEM)\"
endif
ifdef BOARD_SYSTEM_DEVICE
LOCAL_CFLAGS += -DSYSTEM_DEVICE=\"$(BOARD_SYSTEM_DEVICE)\"
endif
ifdef BOARD_SYSTEM_FILESYSTEM
LOCAL_CFLAGS += -DSYSTEM_FILESYSTEM=\"$(BOARD_SYSTEM_FILESYSTEM)\"
endif
ifdef BOARD_HAS_DATADATA
LOCAL_CFLAGS += -DHAS_DATADATA
endif
ifdef BOARD_DATA_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DDATA_FILESYSTEM_OPTIONS=\"$(BOARD_DATA_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_DATADATA_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DDATADATA_FILESYSTEM_OPTIONS=\"$(BOARD_DATADATA_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_CACHE_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DCACHE_FILESYSTEM_OPTIONS=\"$(BOARD_CACHE_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_SYSTEM_FILESYSTEM_OPTIONS
LOCAL_CFLAGS += -DSYSTEM_FILESYSTEM_OPTIONS=\"$(BOARD_SYSTEM_FILESYSTEM_OPTIONS)\"
endif
ifdef BOARD_HAS_MTD_CACHE
LOCAL_CFLAGS += -DBOARD_HAS_MTD_CACHE
endif
ifdef BOARD_HAS_SMALL_RECOVERY
LOCAL_CFLAGS += -DBOARD_HAS_SMALL_RECOVERY
endif
LOCAL_CFLAGS += -DUSE_EXT4
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_STATIC_LIBRARIES += libext4_utils libz
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses
@ -136,48 +70,59 @@ endif
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES :=
ifeq ($(BOARD_CUSTOM_RECOVERY_KEYMAPPING),)
LOCAL_SRC_FILES += default_recovery_ui.c
LOCAL_SRC_FILES += default_recovery_keys.c
else
LOCAL_SRC_FILES += $(BOARD_CUSTOM_RECOVERY_KEYMAPPING)
endif
LOCAL_STATIC_LIBRARIES += libbusybox libclearsilverregex libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image libmtdutils
LOCAL_STATIC_LIBRARIES += libamend
LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt
LOCAL_STATIC_LIBRARIES += libext4_utils libz
LOCAL_STATIC_LIBRARIES += libminzip libunz libmincrypt
LOCAL_STATIC_LIBRARIES += libedify libbusybox libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image
LOCAL_STATIC_LIBRARIES += libcrecovery libflashutils libmtdutils libmmcutils libbmlutils
ifeq ($(BOARD_USES_BML_OVER_MTD),true)
LOCAL_STATIC_LIBRARIES += libbml_over_mtd
endif
LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
LOCAL_STATIC_LIBRARIES += libstdc++ libc
LOCAL_C_INCLUDES += system/extras/ext4_utils
include $(BUILD_EXECUTABLE)
RECOVERY_LINKS := amend busybox flash_image dump_image mkyaffs2image unyaffs erase_image nandroid reboot
RECOVERY_LINKS := edify busybox flash_image dump_image mkyaffs2image unyaffs erase_image nandroid reboot volume setprop
# nc is provided by external/netcat
SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(RECOVERY_LINKS))
$(SYMLINKS): RECOVERY_BINARY := $(LOCAL_MODULE)
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE)
RECOVERY_SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(RECOVERY_LINKS))
$(RECOVERY_SYMLINKS): RECOVERY_BINARY := $(LOCAL_MODULE)
$(RECOVERY_SYMLINKS): $(LOCAL_INSTALLED_MODULE)
@echo "Symlink: $@ -> $(RECOVERY_BINARY)"
@mkdir -p $(dir $@)
@rm -rf $@
$(hide) ln -sf $(RECOVERY_BINARY) $@
ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
ALL_DEFAULT_INSTALLED_MODULES += $(RECOVERY_SYMLINKS)
# Now let's do recovery symlinks
BUSYBOX_LINKS := $(shell cat external/busybox/busybox-minimal.links)
SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(filter-out $(exclude),$(notdir $(BUSYBOX_LINKS))))
$(SYMLINKS): BUSYBOX_BINARY := busybox
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE)
exclude := tune2fs mke2fs
RECOVERY_BUSYBOX_SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(filter-out $(exclude),$(notdir $(BUSYBOX_LINKS))))
$(RECOVERY_BUSYBOX_SYMLINKS): BUSYBOX_BINARY := busybox
$(RECOVERY_BUSYBOX_SYMLINKS): $(LOCAL_INSTALLED_MODULE)
@echo "Symlink: $@ -> $(BUSYBOX_BINARY)"
@mkdir -p $(dir $@)
@rm -rf $@
$(hide) ln -sf $(BUSYBOX_BINARY) $@
ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
ALL_DEFAULT_INSTALLED_MODULES += $(RECOVERY_BUSYBOX_SYMLINKS)
include $(CLEAR_VARS)
LOCAL_MODULE := nandroid-md5.sh
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
LOCAL_SRC_FILES := nandroid-md5.sh
@ -185,22 +130,37 @@ include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := killrecovery.sh
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
LOCAL_SRC_FILES := killrecovery.sh
include $(BUILD_PREBUILT)
include $(commands_recovery_local_path)/amend/Android.mk
include $(CLEAR_VARS)
LOCAL_SRC_FILES := verifier_test.c verifier.c
LOCAL_MODULE := verifier_test
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := tests
LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(commands_recovery_local_path)/bmlutils/Android.mk
include $(commands_recovery_local_path)/flashutils/Android.mk
include $(commands_recovery_local_path)/libcrecovery/Android.mk
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minelf/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
include $(commands_recovery_local_path)/mmcutils/Android.mk
include $(commands_recovery_local_path)/tools/Android.mk
include $(commands_recovery_local_path)/edify/Android.mk
include $(commands_recovery_local_path)/updater/Android.mk
include $(commands_recovery_local_path)/applypatch/Android.mk
include $(commands_recovery_local_path)/utilities/Android.mk
commands_recovery_local_path :=
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

49
CleanSpec.mk Normal file
View File

@ -0,0 +1,49 @@
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# If you don't need to do a full clean build but would like to touch
# a file or delete some intermediate files, add a clean step to the end
# of the list. These steps will only be run once, if they haven't been
# run before.
#
# E.g.:
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
#
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
# files that are missing or have been moved.
#
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
# Use $(OUT_DIR) to refer to the "out" directory.
#
# If you need to re-do something that's already mentioned, just copy
# the command and add it to the bottom of the list. E.g., if a change
# that you made last week required touching a file and a change you
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************

View File

@ -1,53 +0,0 @@
# Copyright 2007 The Android Open Source Project
#
LOCAL_PATH := $(call my-dir)
amend_src_files := \
amend.c \
lexer.l \
parser_y.y \
ast.c \
symtab.c \
commands.c \
permissions.c \
execute.c
amend_test_files := \
test_symtab.c \
test_commands.c \
test_permissions.c
# "-x c" forces the lex/yacc files to be compiled as c;
# the build system otherwise forces them to be c++.
amend_cflags := -Wall -x c
#
# Build the host-side command line tool
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(amend_src_files) \
$(amend_test_files) \
register.c \
main.c
LOCAL_CFLAGS := $(amend_cflags) -g -O0
LOCAL_MODULE := amend
LOCAL_YACCFLAGS := -v
include $(BUILD_HOST_EXECUTABLE)
#
# Build the device-side library
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(amend_src_files)
LOCAL_SRC_FILES += $(amend_test_files)
LOCAL_CFLAGS := $(amend_cflags)
LOCAL_MODULE := libamend
include $(BUILD_STATIC_LIBRARY)

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include "amend.h"
#include "lexer.h"
extern const AmCommandList *gCommands;
const AmCommandList *
parseAmendScript(const char *buf, size_t bufLen)
{
setLexerInputBuffer(buf, bufLen);
int ret = yyparse();
if (ret != 0) {
return NULL;
}
return gCommands;
}

View File

@ -1,25 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_H_
#define AMEND_H_
#include "ast.h"
#include "execute.h"
const AmCommandList *parseAmendScript(const char *buf, size_t bufLen);
#endif // AMEND_H_

View File

@ -1,198 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "ast.h"
static const char gSpaces[] =
" "
" "
" "
" "
" "
" "
" ";
const int gSpacesMax = sizeof(gSpaces) - 1;
static const char *
pad(int level)
{
level *= 4;
if (level > gSpacesMax) {
level = gSpacesMax;
}
return gSpaces + gSpacesMax - level;
}
void dumpBooleanValue(int level, const AmBooleanValue *booleanValue);
void dumpStringValue(int level, const AmStringValue *stringValue);
void
dumpBooleanExpression(int level, const AmBooleanExpression *booleanExpression)
{
const char *op;
bool unary = false;
switch (booleanExpression->op) {
case AM_BOP_NOT:
op = "NOT";
unary = true;
break;
case AM_BOP_EQ:
op = "EQ";
break;
case AM_BOP_NE:
op = "NE";
break;
case AM_BOP_AND:
op = "AND";
break;
case AM_BOP_OR:
op = "OR";
break;
default:
op = "??";
break;
}
printf("%sBOOLEAN %s {\n", pad(level), op);
dumpBooleanValue(level + 1, booleanExpression->arg1);
if (!unary) {
dumpBooleanValue(level + 1, booleanExpression->arg2);
}
printf("%s}\n", pad(level));
}
void
dumpFunctionArguments(int level, const AmFunctionArguments *functionArguments)
{
int i;
for (i = 0; i < functionArguments->argc; i++) {
dumpStringValue(level, &functionArguments->argv[i]);
}
}
void
dumpFunctionCall(int level, const AmFunctionCall *functionCall)
{
printf("%sFUNCTION %s (\n", pad(level), functionCall->name);
dumpFunctionArguments(level + 1, functionCall->args);
printf("%s)\n", pad(level));
}
void
dumpStringValue(int level, const AmStringValue *stringValue)
{
switch (stringValue->type) {
case AM_SVAL_LITERAL:
printf("%s\"%s\"\n", pad(level), stringValue->u.literal);
break;
case AM_SVAL_FUNCTION:
dumpFunctionCall(level, stringValue->u.function);
break;
default:
printf("%s<UNKNOWN SVAL TYPE %d>\n", pad(level), stringValue->type);
break;
}
}
void
dumpStringComparisonExpression(int level,
const AmStringComparisonExpression *stringComparisonExpression)
{
const char *op;
switch (stringComparisonExpression->op) {
case AM_SOP_LT:
op = "LT";
break;
case AM_SOP_LE:
op = "LE";
break;
case AM_SOP_GT:
op = "GT";
break;
case AM_SOP_GE:
op = "GE";
break;
case AM_SOP_EQ:
op = "EQ";
break;
case AM_SOP_NE:
op = "NE";
break;
default:
op = "??";
break;
}
printf("%sSTRING %s {\n", pad(level), op);
dumpStringValue(level + 1, stringComparisonExpression->arg1);
dumpStringValue(level + 1, stringComparisonExpression->arg2);
printf("%s}\n", pad(level));
}
void
dumpBooleanValue(int level, const AmBooleanValue *booleanValue)
{
switch (booleanValue->type) {
case AM_BVAL_EXPRESSION:
dumpBooleanExpression(level, &booleanValue->u.expression);
break;
case AM_BVAL_STRING_COMPARISON:
dumpStringComparisonExpression(level,
&booleanValue->u.stringComparison);
break;
default:
printf("%s<UNKNOWN BVAL TYPE %d>\n", pad(1), booleanValue->type);
break;
}
}
void
dumpWordList(const AmWordList *wordList)
{
int i;
for (i = 0; i < wordList->argc; i++) {
printf("%s\"%s\"\n", pad(1), wordList->argv[i]);
}
}
void
dumpCommandArguments(const AmCommandArguments *commandArguments)
{
if (commandArguments->booleanArgs) {
dumpBooleanValue(1, commandArguments->u.b);
} else {
dumpWordList(commandArguments->u.w);
}
}
void
dumpCommand(const AmCommand *command)
{
printf("command \"%s\" {\n", command->name);
dumpCommandArguments(command->args);
printf("}\n");
}
void
dumpCommandList(const AmCommandList *commandList)
{
int i;
for (i = 0; i < commandList->commandCount; i++) {
dumpCommand(commandList->commands[i]);
}
}

View File

@ -1,165 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_AST_H_
#define AMEND_AST_H_
#include "commands.h"
typedef struct AmStringValue AmStringValue;
typedef struct {
int argc;
AmStringValue *argv;
} AmFunctionArguments;
/* An internal structure used only by the parser;
* will not appear in the output AST.
xxx try to move this into parser.h
*/
typedef struct AmFunctionArgumentBuilder AmFunctionArgumentBuilder;
struct AmFunctionArgumentBuilder {
AmFunctionArgumentBuilder *next;
AmStringValue *arg;
int argCount;
};
typedef struct AmWordListBuilder AmWordListBuilder;
struct AmWordListBuilder {
AmWordListBuilder *next;
const char *word;
int wordCount;
};
typedef struct {
const char *name;
Function *fn;
AmFunctionArguments *args;
} AmFunctionCall;
/* <string-value> ::=
* <literal-string> |
* <function-call>
*/
struct AmStringValue {
unsigned int line;
enum {
AM_SVAL_LITERAL,
AM_SVAL_FUNCTION,
} type;
union {
const char *literal;
//xxx inline instead of using pointers
AmFunctionCall *function;
} u;
};
/* <string-comparison-expression> ::=
* <string-value> <string-comparison-operator> <string-value>
*/
typedef struct {
unsigned int line;
enum {
AM_SOP_LT,
AM_SOP_LE,
AM_SOP_GT,
AM_SOP_GE,
AM_SOP_EQ,
AM_SOP_NE,
} op;
AmStringValue *arg1;
AmStringValue *arg2;
} AmStringComparisonExpression;
/* <boolean-expression> ::=
* ! <boolean-value> |
* <boolean-value> <binary-boolean-operator> <boolean-value>
*/
typedef struct AmBooleanValue AmBooleanValue;
typedef struct {
unsigned int line;
enum {
AM_BOP_NOT,
AM_BOP_EQ,
AM_BOP_NE,
AM_BOP_AND,
AM_BOP_OR,
} op;
AmBooleanValue *arg1;
AmBooleanValue *arg2;
} AmBooleanExpression;
/* <boolean-value> ::=
* <boolean-expression> |
* <string-comparison-expression>
*/
struct AmBooleanValue {
unsigned int line;
enum {
AM_BVAL_EXPRESSION,
AM_BVAL_STRING_COMPARISON,
} type;
union {
AmBooleanExpression expression;
AmStringComparisonExpression stringComparison;
} u;
};
typedef struct {
unsigned int line;
int argc;
const char **argv;
} AmWordList;
typedef struct {
bool booleanArgs;
union {
AmWordList *w;
AmBooleanValue *b;
} u;
} AmCommandArguments;
typedef struct {
unsigned int line;
const char *name;
Command *cmd;
AmCommandArguments *args;
} AmCommand;
typedef struct {
AmCommand **commands;
int commandCount;
int arraySize;
} AmCommandList;
void dumpCommandList(const AmCommandList *commandList);
#endif // AMEND_AST_H_

View File

@ -1,273 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "symtab.h"
#include "commands.h"
#if 1
#define TRACE(...) printf(__VA_ARGS__)
#else
#define TRACE(...) /**/
#endif
typedef enum {
CMD_TYPE_UNKNOWN = -1,
CMD_TYPE_COMMAND = 0,
CMD_TYPE_FUNCTION
} CommandType;
typedef struct {
const char *name;
void *cookie;
CommandType type;
CommandArgumentType argType;
CommandHook hook;
} CommandEntry;
static struct {
SymbolTable *symbolTable;
bool commandStateInitialized;
} gCommandState;
int
commandInit()
{
if (gCommandState.commandStateInitialized) {
return -1;
}
gCommandState.symbolTable = createSymbolTable();
if (gCommandState.symbolTable == NULL) {
return -1;
}
gCommandState.commandStateInitialized = true;
return 0;
}
void
commandCleanup()
{
if (gCommandState.commandStateInitialized) {
gCommandState.commandStateInitialized = false;
deleteSymbolTable(gCommandState.symbolTable);
gCommandState.symbolTable = NULL;
//xxx need to free the entries and names in the symbol table
}
}
static int
registerCommandInternal(const char *name, CommandType type,
CommandArgumentType argType, CommandHook hook, void *cookie)
{
CommandEntry *entry;
if (!gCommandState.commandStateInitialized) {
return -1;
}
if (name == NULL || hook == NULL) {
return -1;
}
if (type != CMD_TYPE_COMMAND && type != CMD_TYPE_FUNCTION) {
return -1;
}
if (argType != CMD_ARGS_BOOLEAN && argType != CMD_ARGS_WORDS) {
return -1;
}
entry = (CommandEntry *)malloc(sizeof(CommandEntry));
if (entry != NULL) {
entry->name = strdup(name);
if (entry->name != NULL) {
int ret;
entry->cookie = cookie;
entry->type = type;
entry->argType = argType;
entry->hook = hook;
ret = addToSymbolTable(gCommandState.symbolTable,
entry->name, entry->type, entry);
if (ret == 0) {
return 0;
}
}
free(entry);
}
return -1;
}
int
registerCommand(const char *name,
CommandArgumentType argType, CommandHook hook, void *cookie)
{
return registerCommandInternal(name,
CMD_TYPE_COMMAND, argType, hook, cookie);
}
int
registerFunction(const char *name, FunctionHook hook, void *cookie)
{
return registerCommandInternal(name,
CMD_TYPE_FUNCTION, CMD_ARGS_WORDS, (CommandHook)hook, cookie);
}
Command *
findCommand(const char *name)
{
return (Command *)findInSymbolTable(gCommandState.symbolTable,
name, CMD_TYPE_COMMAND);
}
Function *
findFunction(const char *name)
{
return (Function *)findInSymbolTable(gCommandState.symbolTable,
name, CMD_TYPE_FUNCTION);
}
CommandArgumentType
getCommandArgumentType(Command *cmd)
{
CommandEntry *entry = (CommandEntry *)cmd;
if (entry != NULL) {
return entry->argType;
}
return CMD_ARGS_UNKNOWN;
}
static int
callCommandInternal(CommandEntry *entry, int argc, const char *argv[],
PermissionRequestList *permissions)
{
if (entry != NULL && entry->argType == CMD_ARGS_WORDS &&
(argc == 0 || (argc > 0 && argv != NULL)))
{
if (permissions == NULL) {
int i;
for (i = 0; i < argc; i++) {
if (argv[i] == NULL) {
goto bail;
}
}
}
TRACE("calling command %s\n", entry->name);
return entry->hook(entry->name, entry->cookie, argc, argv, permissions);
//xxx if permissions, make sure the entry has added at least one element.
}
bail:
return -1;
}
static int
callBooleanCommandInternal(CommandEntry *entry, bool arg,
PermissionRequestList *permissions)
{
if (entry != NULL && entry->argType == CMD_ARGS_BOOLEAN) {
TRACE("calling boolean command %s\n", entry->name);
return entry->hook(entry->name, entry->cookie, arg ? 1 : 0, NULL,
permissions);
//xxx if permissions, make sure the entry has added at least one element.
}
return -1;
}
int
callCommand(Command *cmd, int argc, const char *argv[])
{
return callCommandInternal((CommandEntry *)cmd, argc, argv, NULL);
}
int
callBooleanCommand(Command *cmd, bool arg)
{
return callBooleanCommandInternal((CommandEntry *)cmd, arg, NULL);
}
int
getCommandPermissions(Command *cmd, int argc, const char *argv[],
PermissionRequestList *permissions)
{
if (permissions != NULL) {
return callCommandInternal((CommandEntry *)cmd, argc, argv,
permissions);
}
return -1;
}
int
getBooleanCommandPermissions(Command *cmd, bool arg,
PermissionRequestList *permissions)
{
if (permissions != NULL) {
return callBooleanCommandInternal((CommandEntry *)cmd, arg,
permissions);
}
return -1;
}
int
callFunctionInternal(CommandEntry *entry, int argc, const char *argv[],
char **result, size_t *resultLen, PermissionRequestList *permissions)
{
if (entry != NULL && entry->argType == CMD_ARGS_WORDS &&
(argc == 0 || (argc > 0 && argv != NULL)))
{
if ((permissions == NULL && result != NULL) ||
(permissions != NULL && result == NULL))
{
if (permissions == NULL) {
/* This is the actual invocation of the function,
* which means that none of the arguments are allowed
* to be NULL.
*/
int i;
for (i = 0; i < argc; i++) {
if (argv[i] == NULL) {
goto bail;
}
}
}
TRACE("calling function %s\n", entry->name);
return ((FunctionHook)entry->hook)(entry->name, entry->cookie,
argc, argv, result, resultLen, permissions);
//xxx if permissions, make sure the entry has added at least one element.
}
}
bail:
return -1;
}
int
callFunction(Function *fn, int argc, const char *argv[],
char **result, size_t *resultLen)
{
return callFunctionInternal((CommandEntry *)fn, argc, argv,
result, resultLen, NULL);
}
int
getFunctionPermissions(Function *fn, int argc, const char *argv[],
PermissionRequestList *permissions)
{
if (permissions != NULL) {
return callFunctionInternal((CommandEntry *)fn, argc, argv,
NULL, NULL, permissions);
}
return -1;
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_COMMANDS_H_
#define AMEND_COMMANDS_H_
#include "permissions.h"
/* Invoke or dry-run a command. If "permissions" is non-NULL,
* the hook should fill it out with the list of files and operations that
* it would need to complete its operation. If "permissions" is NULL,
* the hook should do the actual work specified by its arguments.
*
* When a command is called with non-NULL "permissions", some arguments
* may be NULL. A NULL argument indicates that the argument is actually
* the output of another function, so is not known at permissions time.
* The permissions of leaf-node functions (those that have only literal
* strings as arguments) will get appended to the permissions of the
* functions that call them. However, to be completely safe, functions
* that receive a NULL argument should request the broadest-possible
* permissions for the range of the input argument.
*
* When a boolean command is called, "argc" is the boolean value and
* "argv" is NULL.
*/
typedef int (*CommandHook)(const char *name, void *cookie,
int argc, const char *argv[],
PermissionRequestList *permissions);
int commandInit(void);
void commandCleanup(void);
/*
* Command management
*/
struct Command;
typedef struct Command Command;
typedef enum {
CMD_ARGS_UNKNOWN = -1,
CMD_ARGS_BOOLEAN = 0,
CMD_ARGS_WORDS
} CommandArgumentType;
int registerCommand(const char *name,
CommandArgumentType argType, CommandHook hook, void *cookie);
Command *findCommand(const char *name);
CommandArgumentType getCommandArgumentType(Command *cmd);
int callCommand(Command *cmd, int argc, const char *argv[]);
int callBooleanCommand(Command *cmd, bool arg);
int getCommandPermissions(Command *cmd, int argc, const char *argv[],
PermissionRequestList *permissions);
int getBooleanCommandPermissions(Command *cmd, bool arg,
PermissionRequestList *permissions);
/*
* Function management
*/
typedef int (*FunctionHook)(const char *name, void *cookie,
int argc, const char *argv[],
char **result, size_t *resultLen,
PermissionRequestList *permissions);
struct Function;
typedef struct Function Function;
int registerFunction(const char *name, FunctionHook hook, void *cookie);
Function *findFunction(const char *name);
int callFunction(Function *fn, int argc, const char *argv[],
char **result, size_t *resultLen);
int getFunctionPermissions(Function *fn, int argc, const char *argv[],
PermissionRequestList *permissions);
#endif // AMEND_COMMANDS_H_

View File

@ -1,315 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#undef NDEBUG
#include <assert.h>
#include "ast.h"
#include "execute.h"
typedef struct {
int c;
const char **v;
} StringList;
static int execBooleanValue(ExecContext *ctx,
const AmBooleanValue *booleanValue, bool *result);
static int execStringValue(ExecContext *ctx, const AmStringValue *stringValue,
const char **result);
static int
execBooleanExpression(ExecContext *ctx,
const AmBooleanExpression *booleanExpression, bool *result)
{
int ret;
bool arg1, arg2;
bool unary;
assert(ctx != NULL);
assert(booleanExpression != NULL);
assert(result != NULL);
if (ctx == NULL || booleanExpression == NULL || result == NULL) {
return -__LINE__;
}
if (booleanExpression->op == AM_BOP_NOT) {
unary = true;
} else {
unary = false;
}
ret = execBooleanValue(ctx, booleanExpression->arg1, &arg1);
if (ret != 0) return ret;
if (!unary) {
ret = execBooleanValue(ctx, booleanExpression->arg2, &arg2);
if (ret != 0) return ret;
} else {
arg2 = false;
}
switch (booleanExpression->op) {
case AM_BOP_NOT:
*result = !arg1;
break;
case AM_BOP_EQ:
*result = (arg1 == arg2);
break;
case AM_BOP_NE:
*result = (arg1 != arg2);
break;
case AM_BOP_AND:
*result = (arg1 && arg2);
break;
case AM_BOP_OR:
*result = (arg1 || arg2);
break;
default:
return -__LINE__;
}
return 0;
}
static int
execFunctionArguments(ExecContext *ctx,
const AmFunctionArguments *functionArguments, StringList *result)
{
int ret;
assert(ctx != NULL);
assert(functionArguments != NULL);
assert(result != NULL);
if (ctx == NULL || functionArguments == NULL || result == NULL) {
return -__LINE__;
}
result->c = functionArguments->argc;
result->v = (const char **)malloc(result->c * sizeof(const char *));
if (result->v == NULL) {
result->c = 0;
return -__LINE__;
}
int i;
for (i = 0; i < functionArguments->argc; i++) {
ret = execStringValue(ctx, &functionArguments->argv[i], &result->v[i]);
if (ret != 0) {
result->c = 0;
free(result->v);
//TODO: free the individual args, if we're responsible for them.
result->v = NULL;
return ret;
}
}
return 0;
}
static int
execFunctionCall(ExecContext *ctx, const AmFunctionCall *functionCall,
const char **result)
{
int ret;
assert(ctx != NULL);
assert(functionCall != NULL);
assert(result != NULL);
if (ctx == NULL || functionCall == NULL || result == NULL) {
return -__LINE__;
}
StringList args;
ret = execFunctionArguments(ctx, functionCall->args, &args);
if (ret != 0) {
return ret;
}
ret = callFunction(functionCall->fn, args.c, args.v, (char **)result, NULL);
if (ret != 0) {
return ret;
}
//TODO: clean up args
return 0;
}
static int
execStringValue(ExecContext *ctx, const AmStringValue *stringValue,
const char **result)
{
int ret;
assert(ctx != NULL);
assert(stringValue != NULL);
assert(result != NULL);
if (ctx == NULL || stringValue == NULL || result == NULL) {
return -__LINE__;
}
switch (stringValue->type) {
case AM_SVAL_LITERAL:
*result = strdup(stringValue->u.literal);
break;
case AM_SVAL_FUNCTION:
ret = execFunctionCall(ctx, stringValue->u.function, result);
if (ret != 0) {
return ret;
}
break;
default:
return -__LINE__;
}
return 0;
}
static int
execStringComparisonExpression(ExecContext *ctx,
const AmStringComparisonExpression *stringComparisonExpression,
bool *result)
{
int ret;
assert(ctx != NULL);
assert(stringComparisonExpression != NULL);
assert(result != NULL);
if (ctx == NULL || stringComparisonExpression == NULL || result == NULL) {
return -__LINE__;
}
const char *arg1, *arg2;
ret = execStringValue(ctx, stringComparisonExpression->arg1, &arg1);
if (ret != 0) {
return ret;
}
ret = execStringValue(ctx, stringComparisonExpression->arg2, &arg2);
if (ret != 0) {
return ret;
}
int cmp = strcmp(arg1, arg2);
switch (stringComparisonExpression->op) {
case AM_SOP_LT:
*result = (cmp < 0);
break;
case AM_SOP_LE:
*result = (cmp <= 0);
break;
case AM_SOP_GT:
*result = (cmp > 0);
break;
case AM_SOP_GE:
*result = (cmp >= 0);
break;
case AM_SOP_EQ:
*result = (cmp == 0);
break;
case AM_SOP_NE:
*result = (cmp != 0);
break;
default:
return -__LINE__;
break;
}
return 0;
}
static int
execBooleanValue(ExecContext *ctx, const AmBooleanValue *booleanValue,
bool *result)
{
int ret;
assert(ctx != NULL);
assert(booleanValue != NULL);
assert(result != NULL);
if (ctx == NULL || booleanValue == NULL || result == NULL) {
return -__LINE__;
}
switch (booleanValue->type) {
case AM_BVAL_EXPRESSION:
ret = execBooleanExpression(ctx, &booleanValue->u.expression, result);
break;
case AM_BVAL_STRING_COMPARISON:
ret = execStringComparisonExpression(ctx,
&booleanValue->u.stringComparison, result);
break;
default:
ret = -__LINE__;
break;
}
return ret;
}
static int
execCommand(ExecContext *ctx, const AmCommand *command)
{
int ret;
assert(ctx != NULL);
assert(command != NULL);
if (ctx == NULL || command == NULL) {
return -__LINE__;
}
CommandArgumentType argType;
argType = getCommandArgumentType(command->cmd);
switch (argType) {
case CMD_ARGS_BOOLEAN:
{
bool bVal;
ret = execBooleanValue(ctx, command->args->u.b, &bVal);
if (ret == 0) {
ret = callBooleanCommand(command->cmd, bVal);
}
}
break;
case CMD_ARGS_WORDS:
{
AmWordList *words = command->args->u.w;
ret = callCommand(command->cmd, words->argc, words->argv);
}
break;
default:
ret = -__LINE__;
break;
}
return ret;
}
int
execCommandList(ExecContext *ctx, const AmCommandList *commandList)
{
int i;
for (i = 0; i < commandList->commandCount; i++) {
int ret = execCommand(ctx, commandList->commands[i]);
if (ret != 0) {
int line = commandList->commands[i]->line;
return line > 0 ? line : ret;
}
}
return 0;
}

View File

@ -1,25 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_EXECUTE_H_
#define AMEND_EXECUTE_H_
typedef struct ExecContext ExecContext;
/* Returns 0 on success, otherwise the line number that failed. */
int execCommandList(ExecContext *ctx, const AmCommandList *commandList);
#endif // AMEND_EXECUTE_H_

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_LEXER_H_
#define AMEND_LEXER_H_
#define AMEND_LEXER_BUFFER_INPUT 1
void yyerror(const char *msg);
int yylex(void);
#if AMEND_LEXER_BUFFER_INPUT
void setLexerInputBuffer(const char *buf, size_t buflen);
#else
#include <stdio.h>
void yyset_in(FILE *in_str);
#endif
const char *tokenToString(int token);
typedef enum {
AM_UNKNOWN_ARGS,
AM_WORD_ARGS,
AM_BOOLEAN_ARGS,
} AmArgumentType;
void setLexerArgumentType(AmArgumentType type);
int getLexerLineNumber(void);
#endif // AMEND_LEXER_H_

View File

@ -1,299 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
%{
#include <stdio.h>
#include <stdlib.h>
#include "ast.h"
#include "lexer.h"
#include "parser.h"
const char *tokenToString(int token)
{
static char scratch[128];
switch (token) {
case TOK_AND:
return "&&";
case TOK_OR:
return "||";
case TOK_EQ:
return "==";
case TOK_NE:
return "!=";
case TOK_GE:
return ">=";
case TOK_LE:
return "<=";
case TOK_EOF:
return "EOF";
case TOK_EOL:
return "EOL\n";
case TOK_STRING:
snprintf(scratch, sizeof(scratch),
"STRING<%s>", yylval.literalString);
return scratch;
case TOK_IDENTIFIER:
snprintf(scratch, sizeof(scratch), "IDENTIFIER<%s>",
yylval.literalString);
return scratch;
case TOK_WORD:
snprintf(scratch, sizeof(scratch), "WORD<%s>",
yylval.literalString);
return scratch;
default:
if (token > ' ' && token <= '~') {
scratch[0] = (char)token;
scratch[1] = '\0';
} else {
snprintf(scratch, sizeof(scratch), "??? <%d>", token);
}
return scratch;
}
}
typedef struct {
char *value;
char *nextc;
unsigned int alloc_size;
} AmString;
static int addCharToString(AmString *str, char c)
{
if ((unsigned int)(str->nextc - str->value) >= str->alloc_size) {
char *new_value;
unsigned int new_size;
new_size = (str->alloc_size + 1) * 2;
if (new_size < 64) {
new_size = 64;
}
new_value = (char *)realloc(str->value, new_size);
if (new_value == NULL) {
yyerror("out of memory");
return -1;
}
str->nextc = str->nextc - str->value + new_value;
str->value = new_value;
str->alloc_size = new_size;
}
*str->nextc++ = c;
return 0;
}
static int setString(AmString *str, const char *p)
{
str->nextc = str->value;
while (*p != '\0') {
//TODO: add the whole string at once
addCharToString(str, *p++);
}
return addCharToString(str, '\0');
}
static AmString gStr = { NULL, NULL, 0 };
static int gLineNumber = 1;
static AmArgumentType gArgumentType = AM_UNKNOWN_ARGS;
static const char *gErrorMessage = NULL;
#if AMEND_LEXER_BUFFER_INPUT
static const char *gInputBuffer;
static const char *gInputBufferNext;
static const char *gInputBufferEnd;
# define YY_INPUT(buf, result, max_size) \
do { \
int nbytes = gInputBufferEnd - gInputBufferNext; \
if (nbytes > 0) { \
if (nbytes > max_size) { \
nbytes = max_size; \
} \
memcpy(buf, gInputBufferNext, nbytes); \
gInputBufferNext += nbytes; \
result = nbytes; \
} else { \
result = YY_NULL; \
} \
} while (false)
#endif // AMEND_LEXER_BUFFER_INPUT
%}
%option noyywrap
%x QUOTED_STRING BOOLEAN WORDS
ident [a-zA-Z_][a-zA-Z_0-9]*
word [^ \t\r\n"]+
%%
/* This happens at the beginning of each call to yylex().
*/
if (gArgumentType == AM_WORD_ARGS) {
BEGIN(WORDS);
} else if (gArgumentType == AM_BOOLEAN_ARGS) {
BEGIN(BOOLEAN);
}
/*xxx require everything to be 7-bit-clean, printable characters */
<INITIAL>{
{ident}/[ \t\r\n] {
/* The only token we recognize in the initial
* state is an identifier followed by whitespace.
*/
setString(&gStr, yytext);
yylval.literalString = gStr.value;
return TOK_IDENTIFIER;
}
}
<BOOLEAN>{
{ident} {
/* Non-quoted identifier-style string */
setString(&gStr, yytext);
yylval.literalString = gStr.value;
return TOK_IDENTIFIER;
}
"&&" return TOK_AND;
"||" return TOK_OR;
"==" return TOK_EQ;
"!=" return TOK_NE;
">=" return TOK_GE;
"<=" return TOK_LE;
[<>()!,] return yytext[0];
}
/* Double-quoted string handling */
<WORDS,BOOLEAN>\" {
/* Initial quote */
gStr.nextc = gStr.value;
BEGIN(QUOTED_STRING);
}
<QUOTED_STRING>{
\" {
/* Closing quote */
BEGIN(INITIAL);
addCharToString(&gStr, '\0');
yylval.literalString = gStr.value;
if (gArgumentType == AM_WORD_ARGS) {
return TOK_WORD;
} else {
return TOK_STRING;
}
}
<<EOF>> |
\n {
/* Unterminated string */
yyerror("unterminated string");
return TOK_ERROR;
}
\\\" {
/* Escaped quote */
addCharToString(&gStr, '"');
}
\\\\ {
/* Escaped backslash */
addCharToString(&gStr, '\\');
}
\\. {
/* No other escapes allowed. */
gErrorMessage = "illegal escape";
return TOK_ERROR;
}
[^\\\n\"]+ {
/* String contents */
char *p = yytext;
while (*p != '\0') {
/* TODO: add the whole string at once */
addCharToString(&gStr, *p++);
}
}
}
<WORDS>{
/*xxx look out for backslashes; escape backslashes and quotes */
/*xxx if a quote is right against a char, we should append */
{word} {
/* Whitespace-separated word */
setString(&gStr, yytext);
yylval.literalString = gStr.value;
return TOK_WORD;
}
}
<INITIAL,WORDS,BOOLEAN>{
\n {
/* Count lines */
gLineNumber++;
gArgumentType = AM_UNKNOWN_ARGS;
BEGIN(INITIAL);
return TOK_EOL;
}
/*xxx backslashes to extend lines? */
/* Skip whitespace and comments.
*/
[ \t\r]+ ;
#.* ;
. {
/* Fail on anything we didn't expect. */
gErrorMessage = "unexpected character";
return TOK_ERROR;
}
}
%%
void
yyerror(const char *msg)
{
if (!strcmp(msg, "syntax error") && gErrorMessage != NULL) {
msg = gErrorMessage;
gErrorMessage = NULL;
}
fprintf(stderr, "line %d: %s at '%s'\n", gLineNumber, msg, yytext);
}
#if AMEND_LEXER_BUFFER_INPUT
void
setLexerInputBuffer(const char *buf, size_t buflen)
{
gLineNumber = 1;
gInputBuffer = buf;
gInputBufferNext = gInputBuffer;
gInputBufferEnd = gInputBuffer + buflen;
}
#endif // AMEND_LEXER_BUFFER_INPUT
void
setLexerArgumentType(AmArgumentType type)
{
gArgumentType = type;
}
int
getLexerLineNumber(void)
{
return gLineNumber;
}

View File

@ -1,195 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ast.h"
#include "lexer.h"
#include "parser.h"
#include "register.h"
#include "execute.h"
void
lexTest()
{
int token;
do {
token = yylex();
if (token == 0) {
printf(" EOF");
fflush(stdout);
break;
} else {
printf(" %s", tokenToString(token));
fflush(stdout);
if (token == TOK_IDENTIFIER) {
if (strcmp(yylval.literalString, "assert") == 0) {
setLexerArgumentType(AM_BOOLEAN_ARGS);
} else {
setLexerArgumentType(AM_WORD_ARGS);
}
do {
token = yylex();
printf(" %s", tokenToString(token));
fflush(stdout);
} while (token != TOK_EOL && token != TOK_EOF && token != 0);
} else if (token != TOK_EOL) {
fprintf(stderr, "syntax error: expected identifier\n");
break;
}
}
} while (token != 0);
printf("\n");
}
void
usage()
{
printf("usage: amend [--debug-lex|--debug-ast] [<filename>]\n");
exit(1);
}
extern const AmCommandList *gCommands;
int
main(int argc, char *argv[])
{
FILE *inputFile = NULL;
bool debugLex = false;
bool debugAst = false;
const char *fileName = NULL;
int err;
#if 1
extern int test_symtab(void);
int ret = test_symtab();
if (ret != 0) {
fprintf(stderr, "test_symtab() failed: %d\n", ret);
exit(ret);
}
extern int test_cmd_fn(void);
ret = test_cmd_fn();
if (ret != 0) {
fprintf(stderr, "test_cmd_fn() failed: %d\n", ret);
exit(ret);
}
extern int test_permissions(void);
ret = test_permissions();
if (ret != 0) {
fprintf(stderr, "test_permissions() failed: %d\n", ret);
exit(ret);
}
#endif
argc--;
argv++;
while (argc > 0) {
if (strcmp("--debug-lex", argv[0]) == 0) {
debugLex = true;
} else if (strcmp("--debug-ast", argv[0]) == 0) {
debugAst = true;
} else if (argv[0][0] == '-') {
fprintf(stderr, "amend: Unknown option \"%s\"\n", argv[0]);
usage();
} else {
fileName = argv[0];
}
argc--;
argv++;
}
if (fileName != NULL) {
inputFile = fopen(fileName, "r");
if (inputFile == NULL) {
fprintf(stderr, "amend: Can't open input file '%s'\n", fileName);
usage();
}
}
commandInit();
//xxx clean up
err = registerUpdateCommands();
if (err < 0) {
fprintf(stderr, "amend: Error registering commands: %d\n", err);
exit(-err);
}
err = registerUpdateFunctions();
if (err < 0) {
fprintf(stderr, "amend: Error registering functions: %d\n", err);
exit(-err);
}
#if AMEND_LEXER_BUFFER_INPUT
if (inputFile == NULL) {
fprintf(stderr, "amend: No input file\n");
usage();
}
char *fileData;
int fileDataLen;
fseek(inputFile, 0, SEEK_END);
fileDataLen = ftell(inputFile);
rewind(inputFile);
if (fileDataLen < 0) {
fprintf(stderr, "amend: Can't get file length\n");
exit(2);
} else if (fileDataLen == 0) {
printf("amend: Empty input file\n");
exit(0);
}
fileData = (char *)malloc(fileDataLen + 1);
if (fileData == NULL) {
fprintf(stderr, "amend: Can't allocate %d bytes\n", fileDataLen + 1);
exit(2);
}
size_t nread = fread(fileData, 1, fileDataLen, inputFile);
if (nread != (size_t)fileDataLen) {
fprintf(stderr, "amend: Didn't read %d bytes, only %zd\n", fileDataLen,
nread);
exit(2);
}
fileData[fileDataLen] = '\0';
setLexerInputBuffer(fileData, fileDataLen);
#else
if (inputFile == NULL) {
inputFile = stdin;
}
yyset_in(inputFile);
#endif
if (debugLex) {
lexTest();
} else {
int ret = yyparse();
if (ret != 0) {
fprintf(stderr, "amend: Parse failed (%d)\n", ret);
exit(2);
} else {
if (debugAst) {
dumpCommandList(gCommands);
}
printf("amend: Parse successful.\n");
ret = execCommandList((ExecContext *)1, gCommands);
if (ret != 0) {
fprintf(stderr, "amend: Execution failed (%d)\n", ret);
exit(3);
}
printf("amend: Execution successful.\n");
}
}
return 0;
}

View File

@ -1,430 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
%{
#undef NDEBUG
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "ast.h"
#include "lexer.h"
#include "commands.h"
void yyerror(const char *msg);
int yylex(void);
#define STRING_COMPARISON(out, a1, sop, a2) \
do { \
out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \
if (out == NULL) { \
YYABORT; \
} \
out->type = AM_BVAL_STRING_COMPARISON; \
out->u.stringComparison.op = sop; \
out->u.stringComparison.arg1 = a1; \
out->u.stringComparison.arg2 = a2; \
} while (false)
#define BOOLEAN_EXPRESSION(out, a1, bop, a2) \
do { \
out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \
if (out == NULL) { \
YYABORT; \
} \
out->type = AM_BVAL_EXPRESSION; \
out->u.expression.op = bop; \
out->u.expression.arg1 = a1; \
out->u.expression.arg2 = a2; \
} while (false)
AmCommandList *gCommands = NULL;
%}
%start lines
%union {
char *literalString;
AmFunctionArgumentBuilder *functionArgumentBuilder;
AmFunctionArguments *functionArguments;
AmFunctionCall *functionCall;
AmStringValue *stringValue;
AmBooleanValue *booleanValue;
AmWordListBuilder *wordListBuilder;
AmCommandArguments *commandArguments;
AmCommand *command;
AmCommandList *commandList;
}
%token TOK_AND TOK_OR TOK_EQ TOK_NE TOK_GE TOK_LE TOK_EOF TOK_EOL TOK_ERROR
%token <literalString> TOK_STRING TOK_IDENTIFIER TOK_WORD
%type <commandList> lines
%type <command> command line
%type <functionArgumentBuilder> function_arguments
%type <functionArguments> function_arguments_or_empty
%type <functionCall> function_call
%type <literalString> function_name
%type <stringValue> string_value
%type <booleanValue> boolean_expression
%type <wordListBuilder> word_list
%type <commandArguments> arguments
/* Operator precedence, weakest to strongest.
* Same as C/Java precedence.
*/
%left TOK_OR
%left TOK_AND
%left TOK_EQ TOK_NE
%left '<' '>' TOK_LE TOK_GE
%right '!'
%%
lines : /* empty */
{
$$ = (AmCommandList *)malloc(sizeof(AmCommandList));
if ($$ == NULL) {
YYABORT;
}
gCommands = $$;
$$->arraySize = 64;
$$->commandCount = 0;
$$->commands = (AmCommand **)malloc(
sizeof(AmCommand *) * $$->arraySize);
if ($$->commands == NULL) {
YYABORT;
}
}
| lines line
{
if ($2 != NULL) {
if ($1->commandCount >= $1->arraySize) {
AmCommand **newArray;
newArray = (AmCommand **)realloc($$->commands,
sizeof(AmCommand *) * $$->arraySize * 2);
if (newArray == NULL) {
YYABORT;
}
$$->commands = newArray;
$$->arraySize *= 2;
}
$1->commands[$1->commandCount++] = $2;
}
}
;
line : line_ending
{
$$ = NULL; /* ignore blank lines */
}
| command arguments line_ending
{
$$ = $1;
$$->args = $2;
setLexerArgumentType(AM_UNKNOWN_ARGS);
}
;
command : TOK_IDENTIFIER
{
Command *cmd = findCommand($1);
if (cmd == NULL) {
fprintf(stderr, "Unknown command \"%s\"\n", $1);
YYABORT;
}
$$ = (AmCommand *)malloc(sizeof(AmCommand));
if ($$ == NULL) {
YYABORT;
}
$$->line = getLexerLineNumber();
$$->name = strdup($1);
if ($$->name == NULL) {
YYABORT;
}
$$->args = NULL;
CommandArgumentType argType = getCommandArgumentType(cmd);
if (argType == CMD_ARGS_BOOLEAN) {
setLexerArgumentType(AM_BOOLEAN_ARGS);
} else {
setLexerArgumentType(AM_WORD_ARGS);
}
$$->cmd = cmd;
}
;
line_ending :
TOK_EOL
| TOK_EOF
;
arguments : boolean_expression
{
$$ = (AmCommandArguments *)malloc(
sizeof(AmCommandArguments));
if ($$ == NULL) {
YYABORT;
}
$$->booleanArgs = true;
$$->u.b = $1;
}
| word_list
{
/* Convert the builder list into an array.
* Do it in reverse order; the words were pushed
* onto the list in LIFO order.
*/
AmWordList *w = (AmWordList *)malloc(sizeof(AmWordList));
if (w == NULL) {
YYABORT;
}
if ($1 != NULL) {
AmWordListBuilder *words = $1;
w->argc = words->wordCount;
w->argv = (const char **)malloc(w->argc *
sizeof(char *));
if (w->argv == NULL) {
YYABORT;
}
int i;
for (i = w->argc; words != NULL && i > 0; --i) {
AmWordListBuilder *f = words;
w->argv[i-1] = words->word;
words = words->next;
free(f);
}
assert(i == 0);
assert(words == NULL);
} else {
w->argc = 0;
w->argv = NULL;
}
$$ = (AmCommandArguments *)malloc(
sizeof(AmCommandArguments));
if ($$ == NULL) {
YYABORT;
}
$$->booleanArgs = false;
$$->u.w = w;
}
;
word_list : /* empty */
{ $$ = NULL; }
| word_list TOK_WORD
{
if ($1 == NULL) {
$$ = (AmWordListBuilder *)malloc(
sizeof(AmWordListBuilder));
if ($$ == NULL) {
YYABORT;
}
$$->next = NULL;
$$->wordCount = 1;
} else {
$$ = (AmWordListBuilder *)malloc(
sizeof(AmWordListBuilder));
if ($$ == NULL) {
YYABORT;
}
$$->next = $1;
$$->wordCount = $$->next->wordCount + 1;
}
$$->word = strdup($2);
if ($$->word == NULL) {
YYABORT;
}
}
;
boolean_expression :
'!' boolean_expression
{
$$ = (AmBooleanValue *)malloc(sizeof(AmBooleanValue));
if ($$ == NULL) {
YYABORT;
}
$$->type = AM_BVAL_EXPRESSION;
$$->u.expression.op = AM_BOP_NOT;
$$->u.expression.arg1 = $2;
$$->u.expression.arg2 = NULL;
}
/* TODO: if both expressions are literals, evaluate now */
| boolean_expression TOK_AND boolean_expression
{ BOOLEAN_EXPRESSION($$, $1, AM_BOP_AND, $3); }
| boolean_expression TOK_OR boolean_expression
{ BOOLEAN_EXPRESSION($$, $1, AM_BOP_OR, $3); }
| boolean_expression TOK_EQ boolean_expression
{ BOOLEAN_EXPRESSION($$, $1, AM_BOP_EQ, $3); }
| boolean_expression TOK_NE boolean_expression
{ BOOLEAN_EXPRESSION($$, $1, AM_BOP_NE, $3); }
| '(' boolean_expression ')'
{ $$ = $2; }
/* TODO: if both strings are literals, evaluate now */
| string_value '<' string_value
{ STRING_COMPARISON($$, $1, AM_SOP_LT, $3); }
| string_value '>' string_value
{ STRING_COMPARISON($$, $1, AM_SOP_GT, $3); }
| string_value TOK_EQ string_value
{ STRING_COMPARISON($$, $1, AM_SOP_EQ, $3); }
| string_value TOK_NE string_value
{ STRING_COMPARISON($$, $1, AM_SOP_NE, $3); }
| string_value TOK_LE string_value
{ STRING_COMPARISON($$, $1, AM_SOP_LE, $3); }
| string_value TOK_GE string_value
{ STRING_COMPARISON($$, $1, AM_SOP_GE, $3); }
;
string_value :
TOK_IDENTIFIER
{
$$ = (AmStringValue *)malloc(sizeof(AmStringValue));
if ($$ == NULL) {
YYABORT;
}
$$->type = AM_SVAL_LITERAL;
$$->u.literal = strdup($1);
if ($$->u.literal == NULL) {
YYABORT;
}
}
| TOK_STRING
{
$$ = (AmStringValue *)malloc(sizeof(AmStringValue));
if ($$ == NULL) {
YYABORT;
}
$$->type = AM_SVAL_LITERAL;
$$->u.literal = strdup($1);
if ($$->u.literal == NULL) {
YYABORT;
}
}
| function_call
{
$$ = (AmStringValue *)malloc(sizeof(AmStringValue));
if ($$ == NULL) {
YYABORT;
}
$$->type = AM_SVAL_FUNCTION;
$$->u.function = $1;
}
;
/* We can't just say
* TOK_IDENTIFIER '(' function_arguments_or_empty ')'
* because parsing function_arguments_or_empty will clobber
* the underlying string that yylval.literalString points to.
*/
function_call :
function_name '(' function_arguments_or_empty ')'
{
Function *fn = findFunction($1);
if (fn == NULL) {
fprintf(stderr, "Unknown function \"%s\"\n", $1);
YYABORT;
}
$$ = (AmFunctionCall *)malloc(sizeof(AmFunctionCall));
if ($$ == NULL) {
YYABORT;
}
$$->name = $1;
if ($$->name == NULL) {
YYABORT;
}
$$->fn = fn;
$$->args = $3;
}
;
function_name :
TOK_IDENTIFIER
{
$$ = strdup($1);
}
;
function_arguments_or_empty :
/* empty */
{
$$ = (AmFunctionArguments *)malloc(
sizeof(AmFunctionArguments));
if ($$ == NULL) {
YYABORT;
}
$$->argc = 0;
$$->argv = NULL;
}
| function_arguments
{
AmFunctionArgumentBuilder *args = $1;
assert(args != NULL);
/* Convert the builder list into an array.
* Do it in reverse order; the args were pushed
* onto the list in LIFO order.
*/
$$ = (AmFunctionArguments *)malloc(
sizeof(AmFunctionArguments));
if ($$ == NULL) {
YYABORT;
}
$$->argc = args->argCount;
$$->argv = (AmStringValue *)malloc(
$$->argc * sizeof(AmStringValue));
if ($$->argv == NULL) {
YYABORT;
}
int i;
for (i = $$->argc; args != NULL && i > 0; --i) {
AmFunctionArgumentBuilder *f = args;
$$->argv[i-1] = *args->arg;
args = args->next;
free(f->arg);
free(f);
}
assert(i == 0);
assert(args == NULL);
}
;
function_arguments :
string_value
{
$$ = (AmFunctionArgumentBuilder *)malloc(
sizeof(AmFunctionArgumentBuilder));
if ($$ == NULL) {
YYABORT;
}
$$->next = NULL;
$$->argCount = 1;
$$->arg = $1;
}
| function_arguments ',' string_value
{
$$ = (AmFunctionArgumentBuilder *)malloc(
sizeof(AmFunctionArgumentBuilder));
if ($$ == NULL) {
YYABORT;
}
$$->next = $1;
$$->argCount = $$->next->argCount + 1;
$$->arg = $3;
}
;
/* xxx this whole tool needs to be hardened */

View File

@ -1,270 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include "permissions.h"
int
initPermissionRequestList(PermissionRequestList *list)
{
if (list != NULL) {
list->requests = NULL;
list->numRequests = 0;
list->requestsAllocated = 0;
return 0;
}
return -1;
}
int
addPermissionRequestToList(PermissionRequestList *list,
const char *path, bool recursive, unsigned int permissions)
{
if (list == NULL || list->numRequests < 0 ||
list->requestsAllocated < list->numRequests || path == NULL)
{
return -1;
}
if (list->numRequests == list->requestsAllocated) {
int newSize;
PermissionRequest *newRequests;
newSize = list->requestsAllocated * 2;
if (newSize < 16) {
newSize = 16;
}
newRequests = (PermissionRequest *)realloc(list->requests,
newSize * sizeof(PermissionRequest));
if (newRequests == NULL) {
return -2;
}
list->requests = newRequests;
list->requestsAllocated = newSize;
}
PermissionRequest *req;
req = &list->requests[list->numRequests++];
req->path = strdup(path);
if (req->path == NULL) {
list->numRequests--;
return -3;
}
req->recursive = recursive;
req->requested = permissions;
req->allowed = 0;
return 0;
}
void
freePermissionRequestListElements(PermissionRequestList *list)
{
if (list != NULL && list->numRequests >= 0 &&
list->requestsAllocated >= list->numRequests)
{
int i;
for (i = 0; i < list->numRequests; i++) {
free((void *)list->requests[i].path);
}
free(list->requests);
initPermissionRequestList(list);
}
}
/*
* Global permission table
*/
static struct {
Permission *permissions;
int numPermissionEntries;
int allocatedPermissionEntries;
bool permissionStateInitialized;
} gPermissionState = {
#if 1
NULL, 0, 0, false
#else
.permissions = NULL,
.numPermissionEntries = 0,
.allocatedPermissionEntries = 0,
.permissionStateInitialized = false
#endif
};
int
permissionInit()
{
if (gPermissionState.permissionStateInitialized) {
return -1;
}
gPermissionState.permissions = NULL;
gPermissionState.numPermissionEntries = 0;
gPermissionState.allocatedPermissionEntries = 0;
gPermissionState.permissionStateInitialized = true;
//xxx maybe add an "namespace root gets no permissions" fallback by default
return 0;
}
void
permissionCleanup()
{
if (gPermissionState.permissionStateInitialized) {
gPermissionState.permissionStateInitialized = false;
if (gPermissionState.permissions != NULL) {
int i;
for (i = 0; i < gPermissionState.numPermissionEntries; i++) {
free((void *)gPermissionState.permissions[i].path);
}
free(gPermissionState.permissions);
}
}
}
int
getPermissionCount()
{
if (gPermissionState.permissionStateInitialized) {
return gPermissionState.numPermissionEntries;
}
return -1;
}
const Permission *
getPermissionAt(int index)
{
if (!gPermissionState.permissionStateInitialized) {
return NULL;
}
if (index < 0 || index >= gPermissionState.numPermissionEntries) {
return NULL;
}
return &gPermissionState.permissions[index];
}
int
getAllowedPermissions(const char *path, bool recursive,
unsigned int *outAllowed)
{
if (!gPermissionState.permissionStateInitialized) {
return -2;
}
if (outAllowed == NULL) {
return -1;
}
*outAllowed = 0;
if (path == NULL) {
return -1;
}
//TODO: implement this for real.
recursive = false;
*outAllowed = PERMSET_ALL;
return 0;
}
int
countPermissionConflicts(PermissionRequestList *requests, bool updateAllowed)
{
if (!gPermissionState.permissionStateInitialized) {
return -2;
}
if (requests == NULL || requests->requests == NULL ||
requests->numRequests < 0 ||
requests->requestsAllocated < requests->numRequests)
{
return -1;
}
int conflicts = 0;
int i;
for (i = 0; i < requests->numRequests; i++) {
PermissionRequest *req;
unsigned int allowed;
int ret;
req = &requests->requests[i];
ret = getAllowedPermissions(req->path, req->recursive, &allowed);
if (ret < 0) {
return ret;
}
if ((req->requested & ~allowed) != 0) {
conflicts++;
}
if (updateAllowed) {
req->allowed = allowed;
}
}
return conflicts;
}
int
registerPermissionSet(int count, Permission *set)
{
if (!gPermissionState.permissionStateInitialized) {
return -2;
}
if (count < 0 || (count > 0 && set == NULL)) {
return -1;
}
if (count == 0) {
return 0;
}
if (gPermissionState.numPermissionEntries + count >=
gPermissionState.allocatedPermissionEntries)
{
Permission *newList;
int newSize;
newSize = (gPermissionState.allocatedPermissionEntries + count) * 2;
if (newSize < 16) {
newSize = 16;
}
newList = (Permission *)realloc(gPermissionState.permissions,
newSize * sizeof(Permission));
if (newList == NULL) {
return -3;
}
gPermissionState.permissions = newList;
gPermissionState.allocatedPermissionEntries = newSize;
}
Permission *p = &gPermissionState.permissions[
gPermissionState.numPermissionEntries];
int i;
for (i = 0; i < count; i++) {
*p = set[i];
//TODO: cache the strlen of the path
//TODO: normalize; strip off trailing /
p->path = strdup(p->path);
if (p->path == NULL) {
/* If we can't add all of the entries, we don't
* add any of them.
*/
Permission *pp = &gPermissionState.permissions[
gPermissionState.numPermissionEntries];
while (pp != p) {
free((void *)pp->path);
pp++;
}
return -4;
}
p++;
}
gPermissionState.numPermissionEntries += count;
return 0;
}

View File

@ -1,111 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_PERMISSIONS_H_
#define AMEND_PERMISSIONS_H_
#include <stdbool.h>
#define PERM_NONE (0)
#define PERM_STAT (1<<0)
#define PERM_READ (1<<1)
#define PERM_WRITE (1<<2) // including create, delete, mkdir, rmdir
#define PERM_CHMOD (1<<3)
#define PERM_CHOWN (1<<4)
#define PERM_CHGRP (1<<5)
#define PERM_SETUID (1<<6)
#define PERM_SETGID (1<<7)
#define PERMSET_READ (PERM_STAT | PERM_READ)
#define PERMSET_WRITE (PERMSET_READ | PERM_WRITE)
#define PERMSET_ALL \
(PERM_STAT | PERM_READ | PERM_WRITE | PERM_CHMOD | \
PERM_CHOWN | PERM_CHGRP | PERM_SETUID | PERM_SETGID)
typedef struct {
unsigned int requested;
unsigned int allowed;
const char *path;
bool recursive;
} PermissionRequest;
typedef struct {
PermissionRequest *requests;
int numRequests;
int requestsAllocated;
} PermissionRequestList;
/* Properly clear out a PermissionRequestList.
*
* @return 0 if list is non-NULL, negative otherwise.
*/
int initPermissionRequestList(PermissionRequestList *list);
/* Add a permission request to the list, allocating more space
* if necessary.
*
* @return 0 on success or a negative value on failure.
*/
int addPermissionRequestToList(PermissionRequestList *list,
const char *path, bool recursive, unsigned int permissions);
/* Free anything allocated by addPermissionRequestToList(). The caller
* is responsible for freeing the actual PermissionRequestList.
*/
void freePermissionRequestListElements(PermissionRequestList *list);
/*
* Global permission table
*/
typedef struct {
const char *path;
unsigned int allowed;
} Permission;
int permissionInit(void);
void permissionCleanup(void);
/* Returns the allowed permissions for the path in "outAllowed".
* Returns 0 if successful, negative if a parameter or global state
* is bad.
*/
int getAllowedPermissions(const char *path, bool recursive,
unsigned int *outAllowed);
/* More-recently-registered permissions override older permissions.
*/
int registerPermissionSet(int count, Permission *set);
/* Check to make sure that each request is allowed.
*
* @param requests The list of permission requests
* @param updateAllowed If true, update the "allowed" field in each
* element of the list
* @return the number of requests that were denied, or negative if
* an error occurred.
*/
int countPermissionConflicts(PermissionRequestList *requests,
bool updateAllowed);
/* Inspection/testing/debugging functions
*/
int getPermissionCount(void);
const Permission *getPermissionAt(int index);
#endif // AMEND_PERMISSIONS_H_

View File

@ -1,410 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#undef NDEBUG
#include <assert.h>
#include "commands.h"
#include "register.h"
#define UNUSED(p) ((void)(p))
#define CHECK_BOOL() \
do { \
assert(argv == NULL); \
if (argv != NULL) return -1; \
assert(argc == true || argc == false); \
if (argc != true && argc != false) return -1; \
} while (false)
#define CHECK_WORDS() \
do { \
assert(argc >= 0); \
if (argc < 0) return -1; \
assert(argc == 0 || argv != NULL); \
if (argc != 0 && argv == NULL) return -1; \
if (permissions != NULL) { \
int CW_I_; \
for (CW_I_ = 0; CW_I_ < argc; CW_I_++) { \
assert(argv[CW_I_] != NULL); \
if (argv[CW_I_] == NULL) return -1; \
} \
} \
} while (false)
#define CHECK_FN() \
do { \
CHECK_WORDS(); \
if (permissions != NULL) { \
assert(result == NULL); \
if (result != NULL) return -1; \
} else { \
assert(result != NULL); \
if (result == NULL) return -1; \
} \
} while (false)
#define NO_PERMS(perms) \
do { \
PermissionRequestList *NP_PRL_ = (perms); \
if (NP_PRL_ != NULL) { \
int NP_RET_ = addPermissionRequestToList(NP_PRL_, \
"", false, PERM_NONE); \
if (NP_RET_ < 0) { \
/* Returns from the calling function. \
*/ \
return NP_RET_; \
} \
} \
} while (false)
/*
* Command definitions
*/
/* assert <boolexpr>
*/
static int
cmd_assert(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_BOOL();
NO_PERMS(permissions);
/* If our argument is false, return non-zero (failure)
* If our argument is true, return zero (success)
*/
if (argc) {
return 0;
} else {
return 1;
}
}
/* format <root>
*/
static int
cmd_format(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_WORDS();
//xxx
return -1;
}
/* copy_dir <srcdir> <dstdir>
*/
static int
cmd_copy_dir(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_WORDS();
//xxx
return -1;
}
/* delete <srcdir> <dstdir>
*/
static int
cmd_delete(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_WORDS();
//xxx
return -1;
}
/* mark <resource> dirty|clean
*/
static int
cmd_mark(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_WORDS();
//xxx when marking, save the top-level hash at the mark point
// so we can retry on failure. Otherwise the hashes won't match,
// or someone could intentionally dirty the FS to force a downgrade
//xxx
return -1;
}
/* done
*/
static int
cmd_done(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_WORDS();
//xxx
return -1;
}
int
registerUpdateCommands()
{
int ret;
ret = registerCommand("assert", CMD_ARGS_BOOLEAN, cmd_assert, NULL);
if (ret < 0) return ret;
ret = registerCommand("copy_dir", CMD_ARGS_WORDS, cmd_copy_dir, NULL);
if (ret < 0) return ret;
ret = registerCommand("delete", CMD_ARGS_WORDS, cmd_delete, NULL);
if (ret < 0) return ret;
ret = registerCommand("format", CMD_ARGS_WORDS, cmd_format, NULL);
if (ret < 0) return ret;
ret = registerCommand("mark", CMD_ARGS_WORDS, cmd_mark, NULL);
if (ret < 0) return ret;
ret = registerCommand("done", CMD_ARGS_WORDS, cmd_done, NULL);
if (ret < 0) return ret;
//xxx some way to fix permissions
//xxx could have "installperms" commands that build the fs_config list
//xxx along with a "commitperms", and any copy_dir etc. needs to see
// a commitperms before it will work
return 0;
}
/*
* Function definitions
*/
/* update_forced()
*
* Returns "true" if some system setting has determined that
* the update should happen no matter what.
*/
static int
fn_update_forced(const char *name, void *cookie, int argc, const char *argv[],
char **result, size_t *resultLen,
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_FN();
NO_PERMS(permissions);
if (argc != 0) {
fprintf(stderr, "%s: wrong number of arguments (%d)\n",
name, argc);
return 1;
}
//xxx check some global or property
bool force = true;
if (force) {
*result = strdup("true");
} else {
*result = strdup("");
}
if (resultLen != NULL) {
*resultLen = strlen(*result);
}
return 0;
}
/* get_mark(<resource>)
*
* Returns the current mark associated with the provided resource.
*/
static int
fn_get_mark(const char *name, void *cookie, int argc, const char *argv[],
char **result, size_t *resultLen,
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_FN();
NO_PERMS(permissions);
if (argc != 1) {
fprintf(stderr, "%s: wrong number of arguments (%d)\n",
name, argc);
return 1;
}
//xxx look up the value
*result = strdup("");
if (resultLen != NULL) {
*resultLen = strlen(*result);
}
return 0;
}
/* hash_dir(<path-to-directory>)
*/
static int
fn_hash_dir(const char *name, void *cookie, int argc, const char *argv[],
char **result, size_t *resultLen,
PermissionRequestList *permissions)
{
int ret = -1;
UNUSED(name);
UNUSED(cookie);
CHECK_FN();
const char *dir;
if (argc != 1) {
fprintf(stderr, "%s: wrong number of arguments (%d)\n",
name, argc);
return 1;
} else {
dir = argv[0];
}
if (permissions != NULL) {
if (dir == NULL) {
/* The argument is the result of another function.
* Assume the worst case, where the function returns
* the root.
*/
dir = "/";
}
ret = addPermissionRequestToList(permissions, dir, true, PERM_READ);
} else {
//xxx build and return the string
*result = strdup("hashvalue");
if (resultLen != NULL) {
*resultLen = strlen(*result);
}
ret = 0;
}
return ret;
}
/* matches(<str>, <str1> [, <strN>...])
* If <str> matches (strcmp) any of <str1>...<strN>, returns <str>,
* otherwise returns "".
*
* E.g., assert matches(hash_dir("/path"), "hash1", "hash2")
*/
static int
fn_matches(const char *name, void *cookie, int argc, const char *argv[],
char **result, size_t *resultLen,
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_FN();
NO_PERMS(permissions);
if (argc < 2) {
fprintf(stderr, "%s: not enough arguments (%d < 2)\n",
name, argc);
return 1;
}
int i;
for (i = 1; i < argc; i++) {
if (strcmp(argv[0], argv[i]) == 0) {
*result = strdup(argv[0]);
if (resultLen != NULL) {
*resultLen = strlen(*result);
}
return 0;
}
}
*result = strdup("");
if (resultLen != NULL) {
*resultLen = 1;
}
return 0;
}
/* concat(<str>, <str1> [, <strN>...])
* Returns the concatenation of all strings.
*/
static int
fn_concat(const char *name, void *cookie, int argc, const char *argv[],
char **result, size_t *resultLen,
PermissionRequestList *permissions)
{
UNUSED(name);
UNUSED(cookie);
CHECK_FN();
NO_PERMS(permissions);
size_t totalLen = 0;
int i;
for (i = 0; i < argc; i++) {
totalLen += strlen(argv[i]);
}
char *s = (char *)malloc(totalLen + 1);
if (s == NULL) {
return -1;
}
s[totalLen] = '\0';
for (i = 0; i < argc; i++) {
//TODO: keep track of the end to avoid walking the string each time
strcat(s, argv[i]);
}
*result = s;
if (resultLen != NULL) {
*resultLen = strlen(s);
}
return 0;
}
int
registerUpdateFunctions()
{
int ret;
ret = registerFunction("update_forced", fn_update_forced, NULL);
if (ret < 0) return ret;
ret = registerFunction("get_mark", fn_get_mark, NULL);
if (ret < 0) return ret;
ret = registerFunction("hash_dir", fn_hash_dir, NULL);
if (ret < 0) return ret;
ret = registerFunction("matches", fn_matches, NULL);
if (ret < 0) return ret;
ret = registerFunction("concat", fn_concat, NULL);
if (ret < 0) return ret;
return 0;
}

View File

@ -1,23 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_REGISTER_H_
#define AMEND_REGISTER_H_
int registerUpdateCommands(void);
int registerUpdateFunctions(void);
#endif // AMEND_REGISTER_H_

View File

@ -1,132 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include "symtab.h"
#define DEFAULT_TABLE_SIZE 16
typedef struct {
char *symbol;
const void *cookie;
unsigned int flags;
} SymbolTableEntry;
struct SymbolTable {
SymbolTableEntry *table;
int numEntries;
int maxSize;
};
SymbolTable *
createSymbolTable()
{
SymbolTable *tab;
tab = (SymbolTable *)malloc(sizeof(SymbolTable));
if (tab != NULL) {
tab->numEntries = 0;
tab->maxSize = DEFAULT_TABLE_SIZE;
tab->table = (SymbolTableEntry *)malloc(
tab->maxSize * sizeof(SymbolTableEntry));
if (tab->table == NULL) {
free(tab);
tab = NULL;
}
}
return tab;
}
void
deleteSymbolTable(SymbolTable *tab)
{
if (tab != NULL) {
while (tab->numEntries > 0) {
free(tab->table[--tab->numEntries].symbol);
}
free(tab->table);
}
}
void *
findInSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags)
{
int i;
if (tab == NULL || symbol == NULL) {
return NULL;
}
// TODO: Sort the table and binary search
for (i = 0; i < tab->numEntries; i++) {
if (strcmp(tab->table[i].symbol, symbol) == 0 &&
tab->table[i].flags == flags)
{
return (void *)tab->table[i].cookie;
}
}
return NULL;
}
int
addToSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags,
const void *cookie)
{
if (tab == NULL || symbol == NULL || cookie == NULL) {
return -1;
}
/* Make sure that this symbol isn't already in the table.
*/
if (findInSymbolTable(tab, symbol, flags) != NULL) {
return -2;
}
/* Make sure there's enough space for the new entry.
*/
if (tab->numEntries == tab->maxSize) {
SymbolTableEntry *newTable;
int newSize;
newSize = tab->numEntries * 2;
if (newSize < DEFAULT_TABLE_SIZE) {
newSize = DEFAULT_TABLE_SIZE;
}
newTable = (SymbolTableEntry *)realloc(tab->table,
newSize * sizeof(SymbolTableEntry));
if (newTable == NULL) {
return -1;
}
tab->maxSize = newSize;
tab->table = newTable;
}
/* Insert the new entry.
*/
symbol = strdup(symbol);
if (symbol == NULL) {
return -1;
}
// TODO: Sort the table
tab->table[tab->numEntries].symbol = (char *)symbol;
tab->table[tab->numEntries].cookie = cookie;
tab->table[tab->numEntries].flags = flags;
tab->numEntries++;
return 0;
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AMEND_SYMTAB_H_
#define AMEND_SYMTAB_H_
typedef struct SymbolTable SymbolTable;
SymbolTable *createSymbolTable(void);
void deleteSymbolTable(SymbolTable *tab);
/* symbol and cookie must be non-NULL.
*/
int addToSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags,
const void *cookie);
void *findInSymbolTable(SymbolTable *tab, const char *symbol,
unsigned int flags);
#endif // AMEND_SYMTAB_H_

View File

@ -1,538 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#undef NDEBUG
#include <assert.h>
#include "commands.h"
static struct {
bool called;
const char *name;
void *cookie;
int argc;
const char **argv;
PermissionRequestList *permissions;
int returnValue;
char *functionResult;
} gTestCommandState;
static int
testCommand(const char *name, void *cookie, int argc, const char *argv[],
PermissionRequestList *permissions)
{
gTestCommandState.called = true;
gTestCommandState.name = name;
gTestCommandState.cookie = cookie;
gTestCommandState.argc = argc;
gTestCommandState.argv = argv;
gTestCommandState.permissions = permissions;
return gTestCommandState.returnValue;
}
static int
testFunction(const char *name, void *cookie, int argc, const char *argv[],
char **result, size_t *resultLen, PermissionRequestList *permissions)
{
gTestCommandState.called = true;
gTestCommandState.name = name;
gTestCommandState.cookie = cookie;
gTestCommandState.argc = argc;
gTestCommandState.argv = argv;
gTestCommandState.permissions = permissions;
if (result != NULL) {
*result = gTestCommandState.functionResult;
if (resultLen != NULL) {
*resultLen = strlen(*result);
}
}
return gTestCommandState.returnValue;
}
static int
test_commands()
{
Command *cmd;
int ret;
CommandArgumentType argType;
ret = commandInit();
assert(ret == 0);
/* Make sure we can't initialize twice.
*/
ret = commandInit();
assert(ret < 0);
/* Try calling with some bad values.
*/
ret = registerCommand(NULL, CMD_ARGS_UNKNOWN, NULL, NULL);
assert(ret < 0);
ret = registerCommand("hello", CMD_ARGS_UNKNOWN, NULL, NULL);
assert(ret < 0);
ret = registerCommand("hello", CMD_ARGS_WORDS, NULL, NULL);
assert(ret < 0);
cmd = findCommand(NULL);
assert(cmd == NULL);
argType = getCommandArgumentType(NULL);
assert((int)argType < 0);
ret = callCommand(NULL, -1, NULL);
assert(ret < 0);
ret = callBooleanCommand(NULL, false);
assert(ret < 0);
/* Register some commands.
*/
ret = registerCommand("one", CMD_ARGS_WORDS, testCommand,
&gTestCommandState);
assert(ret == 0);
ret = registerCommand("two", CMD_ARGS_WORDS, testCommand,
&gTestCommandState);
assert(ret == 0);
ret = registerCommand("bool", CMD_ARGS_BOOLEAN, testCommand,
&gTestCommandState);
assert(ret == 0);
/* Make sure that all of those commands exist and that their
* argument types are correct.
*/
cmd = findCommand("one");
assert(cmd != NULL);
argType = getCommandArgumentType(cmd);
assert(argType == CMD_ARGS_WORDS);
cmd = findCommand("two");
assert(cmd != NULL);
argType = getCommandArgumentType(cmd);
assert(argType == CMD_ARGS_WORDS);
cmd = findCommand("bool");
assert(cmd != NULL);
argType = getCommandArgumentType(cmd);
assert(argType == CMD_ARGS_BOOLEAN);
/* Make sure that no similar commands exist.
*/
cmd = findCommand("on");
assert(cmd == NULL);
cmd = findCommand("onee");
assert(cmd == NULL);
/* Make sure that a double insertion fails.
*/
ret = registerCommand("one", CMD_ARGS_WORDS, testCommand,
&gTestCommandState);
assert(ret < 0);
/* Make sure that bad args fail.
*/
cmd = findCommand("one");
assert(cmd != NULL);
ret = callCommand(cmd, -1, NULL); // argc must be non-negative
assert(ret < 0);
ret = callCommand(cmd, 1, NULL); // argv can't be NULL if argc > 0
assert(ret < 0);
/* Make sure that you can't make a boolean call on a regular command.
*/
cmd = findCommand("one");
assert(cmd != NULL);
ret = callBooleanCommand(cmd, false);
assert(ret < 0);
/* Make sure that you can't make a regular call on a boolean command.
*/
cmd = findCommand("bool");
assert(cmd != NULL);
ret = callCommand(cmd, 0, NULL);
assert(ret < 0);
/* Set up some arguments.
*/
int argc = 4;
const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
/* Make a call and make sure that it occurred.
*/
cmd = findCommand("one");
assert(cmd != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 25;
gTestCommandState.permissions = (PermissionRequestList *)1;
ret = callCommand(cmd, argc, argv);
//xxx also try calling with a null argv element (should fail)
assert(ret == 25);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "one") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == argc);
assert(gTestCommandState.argv == argv);
assert(gTestCommandState.permissions == NULL);
/* Make a boolean call and make sure that it occurred.
*/
cmd = findCommand("bool");
assert(cmd != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 12;
gTestCommandState.permissions = (PermissionRequestList *)1;
ret = callBooleanCommand(cmd, false);
assert(ret == 12);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "bool") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == 0);
assert(gTestCommandState.argv == NULL);
assert(gTestCommandState.permissions == NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 13;
gTestCommandState.permissions = (PermissionRequestList *)1;
ret = callBooleanCommand(cmd, true);
assert(ret == 13);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "bool") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == 1);
assert(gTestCommandState.argv == NULL);
assert(gTestCommandState.permissions == NULL);
/* Try looking up permissions.
*/
PermissionRequestList permissions;
cmd = findCommand("one");
assert(cmd != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 27;
gTestCommandState.permissions = (PermissionRequestList *)1;
argv[1] = NULL; // null out an arg, which should be ok
ret = getCommandPermissions(cmd, argc, argv, &permissions);
assert(ret == 27);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "one") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == argc);
assert(gTestCommandState.argv == argv);
assert(gTestCommandState.permissions == &permissions);
/* Boolean command permissions
*/
cmd = findCommand("bool");
assert(cmd != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 55;
gTestCommandState.permissions = (PermissionRequestList *)1;
// argv[1] is still NULL
ret = getBooleanCommandPermissions(cmd, true, &permissions);
assert(ret == 55);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "bool") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == 1);
assert(gTestCommandState.argv == NULL);
assert(gTestCommandState.permissions == &permissions);
/* Smoke test commandCleanup().
*/
commandCleanup();
return 0;
}
static int
test_functions()
{
Function *fn;
int ret;
ret = commandInit();
assert(ret == 0);
/* Try calling with some bad values.
*/
ret = registerFunction(NULL, NULL, NULL);
assert(ret < 0);
ret = registerFunction("hello", NULL, NULL);
assert(ret < 0);
fn = findFunction(NULL);
assert(fn == NULL);
ret = callFunction(NULL, -1, NULL, NULL, NULL);
assert(ret < 0);
/* Register some functions.
*/
ret = registerFunction("one", testFunction, &gTestCommandState);
assert(ret == 0);
ret = registerFunction("two", testFunction, &gTestCommandState);
assert(ret == 0);
ret = registerFunction("three", testFunction, &gTestCommandState);
assert(ret == 0);
/* Make sure that all of those functions exist.
* argument types are correct.
*/
fn = findFunction("one");
assert(fn != NULL);
fn = findFunction("two");
assert(fn != NULL);
fn = findFunction("three");
assert(fn != NULL);
/* Make sure that no similar functions exist.
*/
fn = findFunction("on");
assert(fn == NULL);
fn = findFunction("onee");
assert(fn == NULL);
/* Make sure that a double insertion fails.
*/
ret = registerFunction("one", testFunction, &gTestCommandState);
assert(ret < 0);
/* Make sure that bad args fail.
*/
fn = findFunction("one");
assert(fn != NULL);
// argc must be non-negative
ret = callFunction(fn, -1, NULL, (char **)1, NULL);
assert(ret < 0);
// argv can't be NULL if argc > 0
ret = callFunction(fn, 1, NULL, (char **)1, NULL);
assert(ret < 0);
// result can't be NULL
ret = callFunction(fn, 0, NULL, NULL, NULL);
assert(ret < 0);
/* Set up some arguments.
*/
int argc = 4;
const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
/* Make a call and make sure that it occurred.
*/
char *functionResult;
size_t functionResultLen;
fn = findFunction("one");
assert(fn != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 25;
gTestCommandState.functionResult = "1234";
gTestCommandState.permissions = (PermissionRequestList *)1;
functionResult = NULL;
functionResultLen = 55;
ret = callFunction(fn, argc, argv,
&functionResult, &functionResultLen);
//xxx also try calling with a null resultLen arg (should succeed)
//xxx also try calling with a null argv element (should fail)
assert(ret == 25);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "one") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == argc);
assert(gTestCommandState.argv == argv);
assert(gTestCommandState.permissions == NULL);
assert(strcmp(functionResult, "1234") == 0);
assert(functionResultLen == strlen(functionResult));
/* Try looking up permissions.
*/
PermissionRequestList permissions;
fn = findFunction("one");
assert(fn != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 27;
gTestCommandState.permissions = (PermissionRequestList *)1;
argv[1] = NULL; // null out an arg, which should be ok
ret = getFunctionPermissions(fn, argc, argv, &permissions);
assert(ret == 27);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "one") == 0);
assert(gTestCommandState.cookie == &gTestCommandState);
assert(gTestCommandState.argc == argc);
assert(gTestCommandState.argv == argv);
assert(gTestCommandState.permissions == &permissions);
/* Smoke test commandCleanup().
*/
commandCleanup();
return 0;
}
static int
test_interaction()
{
Command *cmd;
Function *fn;
int ret;
ret = commandInit();
assert(ret == 0);
/* Register some commands.
*/
ret = registerCommand("one", CMD_ARGS_WORDS, testCommand, (void *)0xc1);
assert(ret == 0);
ret = registerCommand("two", CMD_ARGS_WORDS, testCommand, (void *)0xc2);
assert(ret == 0);
/* Register some functions, one of which shares a name with a command.
*/
ret = registerFunction("one", testFunction, (void *)0xf1);
assert(ret == 0);
ret = registerFunction("three", testFunction, (void *)0xf3);
assert(ret == 0);
/* Look up each of the commands, and make sure no command exists
* with the name used only by our function.
*/
cmd = findCommand("one");
assert(cmd != NULL);
cmd = findCommand("two");
assert(cmd != NULL);
cmd = findCommand("three");
assert(cmd == NULL);
/* Look up each of the functions, and make sure no function exists
* with the name used only by our command.
*/
fn = findFunction("one");
assert(fn != NULL);
fn = findFunction("two");
assert(fn == NULL);
fn = findFunction("three");
assert(fn != NULL);
/* Set up some arguments.
*/
int argc = 4;
const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
/* Call the overlapping command and make sure that the cookie is correct.
*/
cmd = findCommand("one");
assert(cmd != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 123;
gTestCommandState.permissions = (PermissionRequestList *)1;
ret = callCommand(cmd, argc, argv);
assert(ret == 123);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "one") == 0);
assert((int)gTestCommandState.cookie == 0xc1);
assert(gTestCommandState.argc == argc);
assert(gTestCommandState.argv == argv);
assert(gTestCommandState.permissions == NULL);
/* Call the overlapping function and make sure that the cookie is correct.
*/
char *functionResult;
size_t functionResultLen;
fn = findFunction("one");
assert(fn != NULL);
memset(&gTestCommandState, 0, sizeof(gTestCommandState));
gTestCommandState.called = false;
gTestCommandState.returnValue = 125;
gTestCommandState.functionResult = "5678";
gTestCommandState.permissions = (PermissionRequestList *)2;
functionResult = NULL;
functionResultLen = 66;
ret = callFunction(fn, argc, argv, &functionResult, &functionResultLen);
assert(ret == 125);
assert(gTestCommandState.called);
assert(strcmp(gTestCommandState.name, "one") == 0);
assert((int)gTestCommandState.cookie == 0xf1);
assert(gTestCommandState.argc == argc);
assert(gTestCommandState.argv == argv);
assert(gTestCommandState.permissions == NULL);
assert(strcmp(functionResult, "5678") == 0);
assert(functionResultLen == strlen(functionResult));
/* Clean up.
*/
commandCleanup();
return 0;
}
int
test_cmd_fn()
{
int ret;
ret = test_commands();
if (ret != 0) {
fprintf(stderr, "test_commands() failed: %d\n", ret);
return ret;
}
ret = test_functions();
if (ret != 0) {
fprintf(stderr, "test_functions() failed: %d\n", ret);
return ret;
}
ret = test_interaction();
if (ret != 0) {
fprintf(stderr, "test_interaction() failed: %d\n", ret);
return ret;
}
return 0;
}

View File

@ -1,347 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#undef NDEBUG
#include <assert.h>
#include "permissions.h"
static int
test_permission_list()
{
PermissionRequestList list;
int ret;
int numRequests;
/* Bad parameter
*/
ret = initPermissionRequestList(NULL);
assert(ret < 0);
/* Good parameter
*/
ret = initPermissionRequestList(&list);
assert(ret == 0);
/* Bad parameters
*/
ret = addPermissionRequestToList(NULL, NULL, false, 0);
assert(ret < 0);
ret = addPermissionRequestToList(&list, NULL, false, 0);
assert(ret < 0);
/* Good parameters
*/
numRequests = 0;
ret = addPermissionRequestToList(&list, "one", false, 1);
assert(ret == 0);
numRequests++;
ret = addPermissionRequestToList(&list, "two", false, 2);
assert(ret == 0);
numRequests++;
ret = addPermissionRequestToList(&list, "three", false, 3);
assert(ret == 0);
numRequests++;
ret = addPermissionRequestToList(&list, "recursive", true, 55);
assert(ret == 0);
numRequests++;
/* Validate the list
*/
assert(list.requests != NULL);
assert(list.numRequests == numRequests);
assert(list.numRequests <= list.requestsAllocated);
bool sawOne = false;
bool sawTwo = false;
bool sawThree = false;
bool sawRecursive = false;
int i;
for (i = 0; i < list.numRequests; i++) {
PermissionRequest *req = &list.requests[i];
assert(req->allowed == 0);
/* Order isn't guaranteed, so we have to switch every time.
*/
if (strcmp(req->path, "one") == 0) {
assert(!sawOne);
assert(req->requested == 1);
assert(!req->recursive);
sawOne = true;
} else if (strcmp(req->path, "two") == 0) {
assert(!sawTwo);
assert(req->requested == 2);
assert(!req->recursive);
sawTwo = true;
} else if (strcmp(req->path, "three") == 0) {
assert(!sawThree);
assert(req->requested == 3);
assert(!req->recursive);
sawThree = true;
} else if (strcmp(req->path, "recursive") == 0) {
assert(!sawRecursive);
assert(req->requested == 55);
assert(req->recursive);
sawRecursive = true;
} else {
assert(false);
}
}
assert(sawOne);
assert(sawTwo);
assert(sawThree);
assert(sawRecursive);
/* Smoke test the teardown
*/
freePermissionRequestListElements(&list);
return 0;
}
static int
test_permission_table()
{
int ret;
/* Test the global permissions table.
* Try calling functions without initializing first.
*/
ret = registerPermissionSet(0, NULL);
assert(ret < 0);
ret = countPermissionConflicts((PermissionRequestList *)16, false);
assert(ret < 0);
ret = getPermissionCount();
assert(ret < 0);
const Permission *p;
p = getPermissionAt(0);
assert(p == NULL);
/* Initialize.
*/
ret = permissionInit();
assert(ret == 0);
/* Make sure we can't initialize twice.
*/
ret = permissionInit();
assert(ret < 0);
/* Test the inspection functions.
*/
ret = getPermissionCount();
assert(ret == 0);
p = getPermissionAt(-1);
assert(p == NULL);
p = getPermissionAt(0);
assert(p == NULL);
p = getPermissionAt(1);
assert(p == NULL);
/* Test registerPermissionSet().
* Try some bad parameter values.
*/
ret = registerPermissionSet(-1, NULL);
assert(ret < 0);
ret = registerPermissionSet(1, NULL);
assert(ret < 0);
/* Register some permissions.
*/
Permission p1;
p1.path = "one";
p1.allowed = 1;
ret = registerPermissionSet(1, &p1);
assert(ret == 0);
ret = getPermissionCount();
assert(ret == 1);
Permission p2[2];
p2[0].path = "two";
p2[0].allowed = 2;
p2[1].path = "three";
p2[1].allowed = 3;
ret = registerPermissionSet(2, p2);
assert(ret == 0);
ret = getPermissionCount();
assert(ret == 3);
ret = registerPermissionSet(0, NULL);
assert(ret == 0);
ret = getPermissionCount();
assert(ret == 3);
p1.path = "four";
p1.allowed = 4;
ret = registerPermissionSet(1, &p1);
assert(ret == 0);
/* Make sure the table looks correct.
* Order is important; more-recent additions
* should appear at higher indices.
*/
ret = getPermissionCount();
assert(ret == 4);
int i;
for (i = 0; i < ret; i++) {
const Permission *p;
p = getPermissionAt(i);
assert(p != NULL);
assert(p->allowed == (unsigned int)(i + 1));
switch (i) {
case 0:
assert(strcmp(p->path, "one") == 0);
break;
case 1:
assert(strcmp(p->path, "two") == 0);
break;
case 2:
assert(strcmp(p->path, "three") == 0);
break;
case 3:
assert(strcmp(p->path, "four") == 0);
break;
default:
assert(!"internal error");
break;
}
}
p = getPermissionAt(ret);
assert(p == NULL);
/* Smoke test the teardown
*/
permissionCleanup();
return 0;
}
static int
test_allowed_permissions()
{
int ret;
int numPerms;
/* Make sure these fail before initialization.
*/
ret = countPermissionConflicts((PermissionRequestList *)1, false);
assert(ret < 0);
ret = getAllowedPermissions((const char *)1, false, (unsigned int *)1);
assert(ret < 0);
/* Initialize.
*/
ret = permissionInit();
assert(ret == 0);
/* Make sure countPermissionConflicts() fails with bad parameters.
*/
ret = countPermissionConflicts(NULL, false);
assert(ret < 0);
/* Register a set of permissions.
*/
Permission perms[] = {
{ "/", PERM_NONE },
{ "/stat", PERM_STAT },
{ "/read", PERMSET_READ },
{ "/write", PERMSET_WRITE },
{ "/.stat", PERM_STAT },
{ "/.stat/.read", PERMSET_READ },
{ "/.stat/.read/.write", PERMSET_WRITE },
{ "/.stat/.write", PERMSET_WRITE },
};
numPerms = sizeof(perms) / sizeof(perms[0]);
ret = registerPermissionSet(numPerms, perms);
assert(ret == 0);
/* Build a permission request list.
*/
PermissionRequestList list;
ret = initPermissionRequestList(&list);
assert(ret == 0);
ret = addPermissionRequestToList(&list, "/stat", false, PERM_STAT);
assert(ret == 0);
ret = addPermissionRequestToList(&list, "/read", false, PERM_READ);
assert(ret == 0);
ret = addPermissionRequestToList(&list, "/write", false, PERM_WRITE);
assert(ret == 0);
//TODO: cover more cases once the permission stuff has been implemented
/* All of the requests in the list should be allowed.
*/
ret = countPermissionConflicts(&list, false);
assert(ret == 0);
/* Add a request that will be denied.
*/
ret = addPermissionRequestToList(&list, "/stat", false, 1<<31 | PERM_STAT);
assert(ret == 0);
ret = countPermissionConflicts(&list, false);
assert(ret == 1);
//TODO: more tests
permissionCleanup();
return 0;
}
int
test_permissions()
{
int ret;
ret = test_permission_list();
if (ret != 0) {
fprintf(stderr, "test_permission_list() failed: %d\n", ret);
return ret;
}
ret = test_permission_table();
if (ret != 0) {
fprintf(stderr, "test_permission_table() failed: %d\n", ret);
return ret;
}
ret = test_allowed_permissions();
if (ret != 0) {
fprintf(stderr, "test_permission_table() failed: %d\n", ret);
return ret;
}
return 0;
}

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#undef NDEBUG
#include <assert.h>
#include "symtab.h"
int
test_symtab()
{
SymbolTable *tab;
void *cookie;
int ret;
/* Test creation */
tab = createSymbolTable();
assert(tab != NULL);
/* Smoke-test deletion */
deleteSymbolTable(tab);
tab = createSymbolTable();
assert(tab != NULL);
/* table parameter must be non-NULL. */
ret = addToSymbolTable(NULL, NULL, 0, NULL);
assert(ret < 0);
/* symbol parameter must be non-NULL. */
ret = addToSymbolTable(tab, NULL, 0, NULL);
assert(ret < 0);
/* cookie parameter must be non-NULL. */
ret = addToSymbolTable(tab, "null", 0, NULL);
assert(ret < 0);
/* table parameter must be non-NULL. */
cookie = findInSymbolTable(NULL, NULL, 0);
assert(cookie == NULL);
/* symbol parameter must be non-NULL. */
cookie = findInSymbolTable(tab, NULL, 0);
assert(cookie == NULL);
/* Try some actual inserts.
*/
ret = addToSymbolTable(tab, "one", 0, (void *)1);
assert(ret == 0);
ret = addToSymbolTable(tab, "two", 0, (void *)2);
assert(ret == 0);
ret = addToSymbolTable(tab, "three", 0, (void *)3);
assert(ret == 0);
/* Try some lookups.
*/
cookie = findInSymbolTable(tab, "one", 0);
assert((int)cookie == 1);
cookie = findInSymbolTable(tab, "two", 0);
assert((int)cookie == 2);
cookie = findInSymbolTable(tab, "three", 0);
assert((int)cookie == 3);
/* Try to insert something that's already there.
*/
ret = addToSymbolTable(tab, "one", 0, (void *)1111);
assert(ret < 0);
/* Make sure that the failed duplicate insert didn't
* clobber the original cookie value.
*/
cookie = findInSymbolTable(tab, "one", 0);
assert((int)cookie == 1);
/* Try looking up something that isn't there.
*/
cookie = findInSymbolTable(tab, "FOUR", 0);
assert(cookie == NULL);
/* Try looking up something that's similar to an existing entry.
*/
cookie = findInSymbolTable(tab, "on", 0);
assert(cookie == NULL);
cookie = findInSymbolTable(tab, "onee", 0);
assert(cookie == NULL);
/* Test flags.
* Try inserting something with a different flag.
*/
ret = addToSymbolTable(tab, "ten", 333, (void *)10);
assert(ret == 0);
/* Make sure it's there.
*/
cookie = findInSymbolTable(tab, "ten", 333);
assert((int)cookie == 10);
/* Make sure it's not there when looked up with a different flag.
*/
cookie = findInSymbolTable(tab, "ten", 0);
assert(cookie == NULL);
/* Try inserting something that has the same name as something
* with a different flag.
*/
ret = addToSymbolTable(tab, "one", 333, (void *)11);
assert(ret == 0);
/* Make sure the new entry exists.
*/
cookie = findInSymbolTable(tab, "one", 333);
assert((int)cookie == 11);
/* Make sure the old entry still has the right value.
*/
cookie = findInSymbolTable(tab, "one", 0);
assert((int)cookie == 1);
/* Try deleting again, now that there's stuff in the table.
*/
deleteSymbolTable(tab);
return 0;
}

View File

@ -1 +0,0 @@
I am a jelly donut.

View File

@ -1,2 +0,0 @@
This is a sample no-op test, which does at least serve to verify that the
test harness is working.

View File

@ -1,17 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
echo 'I am a jelly donut.'

View File

@ -1 +0,0 @@
EOF

View File

@ -1 +0,0 @@
Test to make sure that an empty file is accepted properly.

View File

@ -1,17 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
amend --debug-lex input

View File

@ -1,13 +0,0 @@
IDENTIFIER<this_identifier_is_not_assert> EOL
IDENTIFIER<NEITHER_IS_THIS_123> EOL
IDENTIFIER<but_the_next_one_is> EOL
IDENTIFIER<assert> EOL
IDENTIFIER<next_one_is_not_an_identifier> EOL
line 6: unexpected character at '1'
EOF
line 1: unexpected character at '"'
EOF
line 1: unexpected character at '='
EOF
line 1: unexpected character at '9'
EOF

View File

@ -1 +0,0 @@
Test to make sure that simple command names are tokenized properly.

View File

@ -1,6 +0,0 @@
this_identifier_is_not_assert
NEITHER_IS_THIS_123
but_the_next_one_is
assert
next_one_is_not_an_identifier
12not_an_identifier

View File

@ -1 +0,0 @@
"quoted"

View File

@ -1 +0,0 @@
==

View File

@ -1 +0,0 @@
99

View File

@ -1,20 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
amend --debug-lex input
amend --debug-lex input2
amend --debug-lex input3
amend --debug-lex input4

View File

@ -1,5 +0,0 @@
IDENTIFIER<comment_on_this_line> EOL
IDENTIFIER<none_on_this_one> EOL
EOL
EOL
EOF

View File

@ -1 +0,0 @@
Test to make sure that comments are stripped out.

View File

@ -1,4 +0,0 @@
comment_on_this_line # this is a "comment" (with / a bunch) # \\ of stuff \
none_on_this_one
# beginning of line
# preceded by whitespace

View File

@ -1,13 +0,0 @@
IDENTIFIER<test> WORD<string> EOL
IDENTIFIER<test> WORD<string with spaces> EOL
IDENTIFIER<test> WORD<string with "escaped" quotes> EOL
IDENTIFIER<test> WORD<string with \escaped\ backslashes> EOL
IDENTIFIER<test> WORD<string with # a comment character> EOL
EOF
EOL
IDENTIFIER<test1>line 2: unterminated string at '
'
??? <0>
EOL
IDENTIFIER<test1>line 2: illegal escape at '\n'
??? <0>

View File

@ -1 +0,0 @@
Test to make sure that quoted strings are tokenized properly.

View File

@ -1,5 +0,0 @@
test "string"
test "string with spaces"
test "string with \"escaped\" quotes"
test "string with \\escaped\\ backslashes"
test "string with # a comment character"

View File

@ -1,2 +0,0 @@
# This should fail
test1 "unterminated string

View File

@ -1,2 +0,0 @@
# This should fail
test1 "string with illegal escape \n in the middle"

View File

@ -1,19 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
amend --debug-lex input
amend --debug-lex input2
amend --debug-lex input3

View File

@ -1,6 +0,0 @@
IDENTIFIER<test> WORD<this> WORD<has> WORD<a> WORD<bunch> WORD<of> WORD<BARE> WORD<ALPHA> WORD<WORDS> EOL
IDENTIFIER<test> WORD<12> WORD<this> WORD<has(some> WORD<)> WORD<ALPHANUMER1C> WORD<and> WORD<\\> WORD<whatever> WORD<characters> EOL
IDENTIFIER<test> WORD<this> WORD<has> WORD<mixed> WORD<bare> WORD<and quoted> WORD<words> EOL
IDENTIFIER<test> WORD<what> WORD<about> WORD<quotesin the middle?> EOL
IDENTIFIER<test> WORD<"""shouldn't> WORD<be> WORD<a> WORD<quoted> WORD<string> EOL
EOF

View File

@ -1 +0,0 @@
Test to make sure that argument words are tokenized properly.

View File

@ -1,5 +0,0 @@
test this has a bunch of BARE ALPHA WORDS
test 12 this has(some ) ALPHANUMER1C and \\ whatever characters
test this has mixed bare "and quoted" words
test what about quotes"in the middle?"
test \"\"\"shouldn't be a quoted string

View File

@ -1,2 +0,0 @@
# This should fail
test1 "unterminated string

View File

@ -1,2 +0,0 @@
# This should fail
test1 "string with illegal escape \n in the middle"

View File

@ -1,17 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
amend --debug-lex input

View File

@ -1,11 +0,0 @@
IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<112345oldhashvalue1234123> EOL
IDENTIFIER<mark> WORD<SYS:> WORD<dirty> EOL
IDENTIFIER<copy_dir> WORD<PKG:android-files> WORD<SYS:> EOL
IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> EOL
IDENTIFIER<mark> WORD<SYS:> WORD<clean> EOL
IDENTIFIER<done> EOL
IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> , STRING<blah> ) == STRING<112345oldhashvalue1234123> EOL
IDENTIFIER<assert> STRING<true> == STRING<false> EOL
IDENTIFIER<assert> IDENTIFIER<one> ( STRING<abc> , IDENTIFIER<two> ( STRING<def> ) ) == STRING<five> EOL
IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> || IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> EOL
EOF

View File

@ -1 +0,0 @@
An input script similar to one that will actually be used in practice.

View File

@ -1,10 +0,0 @@
assert hash_dir("SYS:") == "112345oldhashvalue1234123"
mark SYS: dirty
copy_dir "PKG:android-files" SYS:
assert hash_dir("SYS:") == "667890newhashvalue6678909"
mark SYS: clean
done
assert hash_dir("SYS:", "blah") == "112345oldhashvalue1234123"
assert "true" == "false"
assert one("abc", two("def")) == "five"
assert hash_dir("SYS:") == "667890newhashvalue6678909" || hash_dir("SYS:") == "667890newhashvalue6678909"

View File

@ -1,17 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
amend --debug-lex input

View File

@ -1,74 +0,0 @@
command "assert" {
STRING EQ {
FUNCTION hash_dir (
"SYS:"
)
"112345oldhashvalue1234123"
}
}
command "mark" {
"SYS:"
"dirty"
}
command "copy_dir" {
"PKG:android-files"
"SYS:"
}
command "assert" {
STRING EQ {
FUNCTION hash_dir (
"SYS:"
)
"667890newhashvalue6678909"
}
}
command "mark" {
"SYS:"
"clean"
}
command "done" {
}
command "assert" {
STRING EQ {
FUNCTION hash_dir (
"SYS:"
"blah"
)
"112345oldhashvalue1234123"
}
}
command "assert" {
STRING EQ {
"true"
"false"
}
}
command "assert" {
STRING NE {
FUNCTION matches (
FUNCTION hash_dir (
"SYS:"
)
"667890newhashvalue6678909"
"999999newhashvalue6678909"
)
""
}
}
command "assert" {
BOOLEAN OR {
STRING EQ {
FUNCTION hash_dir (
"SYS:"
)
"667890newhashvalue6678909"
}
STRING EQ {
FUNCTION hash_dir (
"SYS:"
)
"999999newhashvalue6678909"
}
}
}
amend: Parse successful.

View File

@ -1 +0,0 @@
An input script similar to one that will actually be used in practice.

View File

@ -1,10 +0,0 @@
assert hash_dir("SYS:") == "112345oldhashvalue1234123"
mark SYS: dirty
copy_dir "PKG:android-files" SYS:
assert hash_dir("SYS:") == "667890newhashvalue6678909"
mark SYS: clean
done
assert hash_dir("SYS:", "blah") == "112345oldhashvalue1234123"
assert "true" == "false"
assert matches(hash_dir("SYS:"), "667890newhashvalue6678909", "999999newhashvalue6678909") != ""
assert hash_dir("SYS:") == "667890newhashvalue6678909" || hash_dir("SYS:") == "999999newhashvalue6678909"

View File

@ -1,17 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
amend --debug-ast input

View File

@ -1,150 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
info="info.txt"
run="run"
expected="expected.txt"
output="out.txt"
skip="SKIP"
dev_mode="no"
if [ "x$1" = "x--dev" ]; then
dev_mode="yes"
shift
fi
update_mode="no"
if [ "x$1" = "x--update" ]; then
update_mode="yes"
shift
fi
usage="no"
if [ "x$1" = "x--help" ]; then
usage="yes"
else
if [ "x$1" = "x" ]; then
testdir=`basename "$oldwd"`
else
testdir="$1"
fi
if [ '!' -d "$testdir" ]; then
td2=`echo ${testdir}-*`
if [ '!' -d "$td2" ]; then
echo "${testdir}: no such test directory" 1>&2
usage="yes"
fi
testdir="$td2"
fi
fi
if [ "$usage" = "yes" ]; then
prog=`basename $prog`
(
echo "usage:"
echo " $prog --help Print this message."
echo " $prog testname Run test normally."
echo " $prog --dev testname Development mode (dump to stdout)."
echo " $prog --update testname Update mode (replace expected.txt)."
echo " Omitting the test name uses the current directory as the test."
) 1>&2
exit 1
fi
td_info="$testdir"/"$info"
td_run="$testdir"/"$run"
td_expected="$testdir"/"$expected"
td_skip="$testdir"/"$skip"
if [ -r "$td_skip" ]; then
exit 2
fi
tmpdir=/tmp/test-$$
if [ '!' '(' -r "$td_info" -a -r "$td_run" -a -r "$td_expected" ')' ]; then
echo "${testdir}: missing files" 1>&2
exit 1
fi
# copy the test to a temp dir and run it
echo "${testdir}: running..." 1>&2
rm -rf "$tmpdir"
cp -Rp "$testdir" "$tmpdir"
cd "$tmpdir"
chmod 755 "$run"
#PATH="${progdir}/../build/bin:${PATH}"
good="no"
if [ "$dev_mode" = "yes" ]; then
"./$run" 2>&1
echo "exit status: $?" 1>&2
good="yes"
elif [ "$update_mode" = "yes" ]; then
"./$run" >"${progdir}/$td_expected" 2>&1
good="yes"
else
"./$run" >"$output" 2>&1
cmp -s "$expected" "$output"
if [ "$?" = "0" ]; then
# output == expected
good="yes"
echo "$testdir"': succeeded!' 1>&2
fi
fi
if [ "$good" = "yes" ]; then
cd "$oldwd"
rm -rf "$tmpdir"
exit 0
fi
(
echo "${testdir}: FAILED!"
echo ' '
echo '#################### info'
cat "$info" | sed 's/^/# /g'
echo '#################### diffs'
diff -u "$expected" "$output"
echo '####################'
echo ' '
echo "files left in $tmpdir"
) 1>&2
exit 1

View File

@ -1,69 +0,0 @@
#!/bin/bash
#
# Copyright (C) 2007 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
passed=0
skipped=0
skipNames=""
failed=0
failNames=""
for i in *; do
if [ -d "$i" -a -r "$i" ]; then
./one-test "$i"
status=$?
if [ "$status" = "0" ]; then
((passed += 1))
elif [ "$status" = "2" ]; then
((skipped += 1))
skipNames="$skipNames $i"
else
((failed += 1))
failNames="$failNames $i"
fi
fi
done
echo "passed: $passed test(s)"
echo "skipped: $skipped test(s)"
for i in $skipNames; do
echo "skipped: $i"
done
echo "failed: $failed test(s)"
for i in $failNames; do
echo "failed: $i"
done

57
applypatch/Android.mk Normal file
View File

@ -0,0 +1,57 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := applypatch.c bspatch.c freecache.c imgpatch.c utils.c
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += external/bzip2 external/zlib bootable/recovery
LOCAL_STATIC_LIBRARIES += libmtdutils libmincrypt libbz libz
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := applypatch
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz libminelf
LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := applypatch_static
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz libminelf
LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := imgdiff.c utils.c bsdiff.c
LOCAL_MODULE := imgdiff
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += external/zlib external/bzip2
LOCAL_STATIC_LIBRARIES += libz libbz
include $(BUILD_HOST_EXECUTABLE)

911
applypatch/applypatch.c Normal file
View File

@ -0,0 +1,911 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "mincrypt/sha.h"
#include "applypatch.h"
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
int SaveFileContents(const char* filename, FileContents file);
static int LoadPartitionContents(const char* filename, FileContents* file);
int ParseSha1(const char* str, uint8_t* digest);
static ssize_t FileSink(unsigned char* data, ssize_t len, void* token);
static int mtd_partitions_scanned = 0;
// Read a file into memory; optionally (retouch_flag == RETOUCH_DO_MASK) mask
// the retouched entries back to their original value (such that SHA-1 checks
// don't fail due to randomization); store the file contents and associated
// metadata in *file.
//
// Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file,
int retouch_flag) {
file->data = NULL;
// A special 'filename' beginning with "MTD:" or "EMMC:" means to
// load the contents of a partition.
if (strncmp(filename, "MTD:", 4) == 0 ||
strncmp(filename, "EMMC:", 5) == 0) {
return LoadPartitionContents(filename, file);
}
if (stat(filename, &file->st) != 0) {
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
return -1;
}
file->size = file->st.st_size;
file->data = malloc(file->size);
FILE* f = fopen(filename, "rb");
if (f == NULL) {
printf("failed to open \"%s\": %s\n", filename, strerror(errno));
free(file->data);
file->data = NULL;
return -1;
}
ssize_t bytes_read = fread(file->data, 1, file->size, f);
if (bytes_read != file->size) {
printf("short read of \"%s\" (%ld bytes of %ld)\n",
filename, (long)bytes_read, (long)file->size);
free(file->data);
file->data = NULL;
return -1;
}
fclose(f);
// apply_patch[_check] functions are blind to randomization. Randomization
// is taken care of in [Undo]RetouchBinariesFn. If there is a mismatch
// within a file, this means the file is assumed "corrupt" for simplicity.
if (retouch_flag) {
int32_t desired_offset = 0;
if (retouch_mask_data(file->data, file->size,
&desired_offset, NULL) != RETOUCH_DATA_MATCHED) {
printf("error trying to mask retouch entries\n");
free(file->data);
file->data = NULL;
return -1;
}
}
SHA(file->data, file->size, file->sha1);
return 0;
}
static size_t* size_array;
// comparison function for qsort()ing an int array of indexes into
// size_array[].
static int compare_size_indices(const void* a, const void* b) {
int aa = *(int*)a;
int bb = *(int*)b;
if (size_array[aa] < size_array[bb]) {
return -1;
} else if (size_array[aa] > size_array[bb]) {
return 1;
} else {
return 0;
}
}
void FreeFileContents(FileContents* file) {
if (file) free(file->data);
free(file);
}
// Load the contents of an MTD or EMMC partition into the provided
// FileContents. filename should be a string of the form
// "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..." (or
// "EMMC:<partition_device>:..."). The smallest size_n bytes for
// which that prefix of the partition contents has the corresponding
// sha1 hash will be loaded. It is acceptable for a size value to be
// repeated with different sha1s. Will return 0 on success.
//
// This complexity is needed because if an OTA installation is
// interrupted, the partition might contain either the source or the
// target data, which might be of different lengths. We need to know
// the length in order to read from a partition (there is no
// "end-of-file" marker), so the caller must specify the possible
// lengths and the hash of the data, and we'll do the load expecting
// to find one of those hashes.
enum PartitionType { MTD, EMMC };
static int LoadPartitionContents(const char* filename, FileContents* file) {
char* copy = strdup(filename);
const char* magic = strtok(copy, ":");
enum PartitionType type;
if (strcmp(magic, "MTD") == 0) {
type = MTD;
} else if (strcmp(magic, "EMMC") == 0) {
type = EMMC;
} else {
printf("LoadPartitionContents called with bad filename (%s)\n",
filename);
return -1;
}
const char* partition = strtok(NULL, ":");
int i;
int colons = 0;
for (i = 0; filename[i] != '\0'; ++i) {
if (filename[i] == ':') {
++colons;
}
}
if (colons < 3 || colons%2 == 0) {
printf("LoadPartitionContents called with bad filename (%s)\n",
filename);
}
int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename
int* index = malloc(pairs * sizeof(int));
size_t* size = malloc(pairs * sizeof(size_t));
char** sha1sum = malloc(pairs * sizeof(char*));
for (i = 0; i < pairs; ++i) {
const char* size_str = strtok(NULL, ":");
size[i] = strtol(size_str, NULL, 10);
if (size[i] == 0) {
printf("LoadPartitionContents called with bad size (%s)\n", filename);
return -1;
}
sha1sum[i] = strtok(NULL, ":");
index[i] = i;
}
// sort the index[] array so it indexes the pairs in order of
// increasing size.
size_array = size;
qsort(index, pairs, sizeof(int), compare_size_indices);
MtdReadContext* ctx = NULL;
FILE* dev = NULL;
switch (type) {
case MTD:
if (!mtd_partitions_scanned) {
mtd_scan_partitions();
mtd_partitions_scanned = 1;
}
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
if (mtd == NULL) {
printf("mtd partition \"%s\" not found (loading %s)\n",
partition, filename);
return -1;
}
ctx = mtd_read_partition(mtd);
if (ctx == NULL) {
printf("failed to initialize read of mtd partition \"%s\"\n",
partition);
return -1;
}
break;
case EMMC:
dev = fopen(partition, "rb");
if (dev == NULL) {
printf("failed to open emmc partition \"%s\": %s\n",
partition, strerror(errno));
return -1;
}
}
SHA_CTX sha_ctx;
SHA_init(&sha_ctx);
uint8_t parsed_sha[SHA_DIGEST_SIZE];
// allocate enough memory to hold the largest size.
file->data = malloc(size[index[pairs-1]]);
char* p = (char*)file->data;
file->size = 0; // # bytes read so far
for (i = 0; i < pairs; ++i) {
// Read enough additional bytes to get us up to the next size
// (again, we're trying the possibilities in order of increasing
// size).
size_t next = size[index[i]] - file->size;
size_t read = 0;
if (next > 0) {
switch (type) {
case MTD:
read = mtd_read_data(ctx, p, next);
break;
case EMMC:
read = fread(p, 1, next, dev);
break;
}
if (next != read) {
printf("short read (%d bytes of %d) for partition \"%s\"\n",
read, next, partition);
free(file->data);
file->data = NULL;
return -1;
}
SHA_update(&sha_ctx, p, read);
file->size += read;
}
// Duplicate the SHA context and finalize the duplicate so we can
// check it against this pair's expected hash.
SHA_CTX temp_ctx;
memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
const uint8_t* sha_so_far = SHA_final(&temp_ctx);
if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) {
printf("failed to parse sha1 %s in %s\n",
sha1sum[index[i]], filename);
free(file->data);
file->data = NULL;
return -1;
}
if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) {
// we have a match. stop reading the partition; we'll return
// the data we've read so far.
printf("partition read matched size %d sha %s\n",
size[index[i]], sha1sum[index[i]]);
break;
}
p += read;
}
switch (type) {
case MTD:
mtd_read_close(ctx);
break;
case EMMC:
fclose(dev);
break;
}
if (i == pairs) {
// Ran off the end of the list of (size,sha1) pairs without
// finding a match.
printf("contents of partition \"%s\" didn't match %s\n",
partition, filename);
free(file->data);
file->data = NULL;
return -1;
}
const uint8_t* sha_final = SHA_final(&sha_ctx);
for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
file->sha1[i] = sha_final[i];
}
// Fake some stat() info.
file->st.st_mode = 0644;
file->st.st_uid = 0;
file->st.st_gid = 0;
free(copy);
free(index);
free(size);
free(sha1sum);
return 0;
}
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
int SaveFileContents(const char* filename, FileContents file) {
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
printf("failed to open \"%s\" for write: %s\n",
filename, strerror(errno));
return -1;
}
ssize_t bytes_written = FileSink(file.data, file.size, &fd);
if (bytes_written != file.size) {
printf("short write of \"%s\" (%ld bytes of %ld) (%s)\n",
filename, (long)bytes_written, (long)file.size,
strerror(errno));
close(fd);
return -1;
}
fsync(fd);
close(fd);
if (chmod(filename, file.st.st_mode) != 0) {
printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) {
printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
return -1;
}
return 0;
}
// Write a memory buffer to 'target' partition, a string of the form
// "MTD:<partition>[:...]" or "EMMC:<partition_device>:". Return 0 on
// success.
int WriteToPartition(unsigned char* data, size_t len,
const char* target) {
char* copy = strdup(target);
const char* magic = strtok(copy, ":");
enum PartitionType type;
if (strcmp(magic, "MTD") == 0) {
type = MTD;
} else if (strcmp(magic, "EMMC") == 0) {
type = EMMC;
} else {
printf("WriteToPartition called with bad target (%s)\n", target);
return -1;
}
const char* partition = strtok(NULL, ":");
if (partition == NULL) {
printf("bad partition target name \"%s\"\n", target);
return -1;
}
switch (type) {
case MTD:
if (!mtd_partitions_scanned) {
mtd_scan_partitions();
mtd_partitions_scanned = 1;
}
const MtdPartition* mtd = mtd_find_partition_by_name(partition);
if (mtd == NULL) {
printf("mtd partition \"%s\" not found for writing\n",
partition);
return -1;
}
MtdWriteContext* ctx = mtd_write_partition(mtd);
if (ctx == NULL) {
printf("failed to init mtd partition \"%s\" for writing\n",
partition);
return -1;
}
size_t written = mtd_write_data(ctx, (char*)data, len);
if (written != len) {
printf("only wrote %d of %d bytes to MTD %s\n",
written, len, partition);
mtd_write_close(ctx);
return -1;
}
if (mtd_erase_blocks(ctx, -1) < 0) {
printf("error finishing mtd write of %s\n", partition);
mtd_write_close(ctx);
return -1;
}
if (mtd_write_close(ctx)) {
printf("error closing mtd write of %s\n", partition);
return -1;
}
break;
case EMMC:
;
FILE* f = fopen(partition, "wb");
if (fwrite(data, 1, len, f) != len) {
printf("short write writing to %s (%s)\n",
partition, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
printf("error closing %s (%s)\n", partition, strerror(errno));
return -1;
}
break;
}
free(copy);
return 0;
}
// Take a string 'str' of 40 hex digits and parse it into the 20
// byte array 'digest'. 'str' may contain only the digest or be of
// the form "<digest>:<anything>". Return 0 on success, -1 on any
// error.
int ParseSha1(const char* str, uint8_t* digest) {
int i;
const char* ps = str;
uint8_t* pd = digest;
for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
int digit;
if (*ps >= '0' && *ps <= '9') {
digit = *ps - '0';
} else if (*ps >= 'a' && *ps <= 'f') {
digit = *ps - 'a' + 10;
} else if (*ps >= 'A' && *ps <= 'F') {
digit = *ps - 'A' + 10;
} else {
return -1;
}
if (i % 2 == 0) {
*pd = digit << 4;
} else {
*pd |= digit;
++pd;
}
}
if (*ps != '\0') return -1;
return 0;
}
// Search an array of sha1 strings for one matching the given sha1.
// Return the index of the match on success, or -1 if no match is
// found.
int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
int num_patches) {
int i;
uint8_t patch_sha1[SHA_DIGEST_SIZE];
for (i = 0; i < num_patches; ++i) {
if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 &&
memcmp(patch_sha1, sha1, SHA_DIGEST_SIZE) == 0) {
return i;
}
}
return -1;
}
// Returns 0 if the contents of the file (argv[2]) or the cached file
// match any of the sha1's on the command line (argv[3:]). Returns
// nonzero otherwise.
int applypatch_check(const char* filename,
int num_patches, char** const patch_sha1_str) {
FileContents file;
file.data = NULL;
// It's okay to specify no sha1s; the check will pass if the
// LoadFileContents is successful. (Useful for reading
// partitions, where the filename encodes the sha1s; no need to
// check them twice.)
if (LoadFileContents(filename, &file, RETOUCH_DO_MASK) != 0 ||
(num_patches > 0 &&
FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) {
printf("file \"%s\" doesn't have any of expected "
"sha1 sums; checking cache\n", filename);
free(file.data);
// If the source file is missing or corrupted, it might be because
// we were killed in the middle of patching it. A copy of it
// should have been made in CACHE_TEMP_SOURCE. If that file
// exists and matches the sha1 we're looking for, the check still
// passes.
if (LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK) != 0) {
printf("failed to load cache file\n");
return 1;
}
if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
printf("cache bits don't match any sha1 for \"%s\"\n", filename);
free(file.data);
return 1;
}
}
free(file.data);
return 0;
}
int ShowLicenses() {
ShowBSDiffLicense();
return 0;
}
ssize_t FileSink(unsigned char* data, ssize_t len, void* token) {
int fd = *(int *)token;
ssize_t done = 0;
ssize_t wrote;
while (done < (ssize_t) len) {
wrote = write(fd, data+done, len-done);
if (wrote <= 0) {
printf("error writing %d bytes: %s\n", (int)(len-done), strerror(errno));
return done;
}
done += wrote;
}
return done;
}
typedef struct {
unsigned char* buffer;
ssize_t size;
ssize_t pos;
} MemorySinkInfo;
ssize_t MemorySink(unsigned char* data, ssize_t len, void* token) {
MemorySinkInfo* msi = (MemorySinkInfo*)token;
if (msi->size - msi->pos < len) {
return -1;
}
memcpy(msi->buffer + msi->pos, data, len);
msi->pos += len;
return len;
}
// Return the amount of free space (in bytes) on the filesystem
// containing filename. filename must exist. Return -1 on error.
size_t FreeSpaceForFile(const char* filename) {
struct statfs sf;
if (statfs(filename, &sf) != 0) {
printf("failed to statfs %s: %s\n", filename, strerror(errno));
return -1;
}
return sf.f_bsize * sf.f_bfree;
}
int CacheSizeCheck(size_t bytes) {
if (MakeFreeSpaceOnCache(bytes) < 0) {
printf("unable to make %ld bytes available on /cache\n", (long)bytes);
return 1;
} else {
return 0;
}
}
// This function applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
// - if the sha1 hash of <target_filename> is <target_sha1_string>,
// does nothing and exits successfully.
//
// - otherwise, if the sha1 hash of <source_filename> is one of the
// entries in <patch_sha1_str>, the corresponding patch from
// <patch_data> (which must be a VAL_BLOB) is applied to produce a
// new file (the type of patch is automatically detected from the
// blob daat). If that new file has sha1 hash <target_sha1_str>,
// moves it to replace <target_filename>, and exits successfully.
// Note that if <source_filename> and <target_filename> are not the
// same, <source_filename> is NOT deleted on success.
// <target_filename> may be the string "-" to mean "the same as
// source_filename".
//
// - otherwise, or if any error is encountered, exits with non-zero
// status.
//
// <source_filename> may refer to a partition to read the source data.
// See the comments for the LoadPartition Contents() function above
// for the format of such a filename.
int applypatch(const char* source_filename,
const char* target_filename,
const char* target_sha1_str,
size_t target_size,
int num_patches,
char** const patch_sha1_str,
Value** patch_data) {
printf("\napplying patch to %s\n", source_filename);
if (target_filename[0] == '-' &&
target_filename[1] == '\0') {
target_filename = source_filename;
}
uint8_t target_sha1[SHA_DIGEST_SIZE];
if (ParseSha1(target_sha1_str, target_sha1) != 0) {
printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
return 1;
}
FileContents copy_file;
FileContents source_file;
const Value* source_patch_value = NULL;
const Value* copy_patch_value = NULL;
int made_copy = 0;
// We try to load the target file into the source_file object.
if (LoadFileContents(target_filename, &source_file,
RETOUCH_DO_MASK) == 0) {
if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
printf("\"%s\" is already target; no patch needed\n",
target_filename);
return 0;
}
}
if (source_file.data == NULL ||
(target_filename != source_filename &&
strcmp(target_filename, source_filename) != 0)) {
// Need to load the source file: either we failed to load the
// target file, or we did but it's different from the source file.
free(source_file.data);
LoadFileContents(source_filename, &source_file,
RETOUCH_DO_MASK);
}
if (source_file.data != NULL) {
int to_use = FindMatchingPatch(source_file.sha1,
patch_sha1_str, num_patches);
if (to_use >= 0) {
source_patch_value = patch_data[to_use];
}
}
if (source_patch_value == NULL) {
free(source_file.data);
printf("source file is bad; trying copy\n");
if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file,
RETOUCH_DO_MASK) < 0) {
// fail.
printf("failed to read copy file\n");
return 1;
}
int to_use = FindMatchingPatch(copy_file.sha1,
patch_sha1_str, num_patches);
if (to_use >= 0) {
copy_patch_value = patch_data[to_use];
}
if (copy_patch_value == NULL) {
// fail.
printf("copy file doesn't match source SHA-1s either\n");
return 1;
}
}
int retry = 1;
SHA_CTX ctx;
int output;
MemorySinkInfo msi;
FileContents* source_to_use;
char* outname;
// assume that target_filename (eg "/system/app/Foo.apk") is located
// on the same filesystem as its top-level directory ("/system").
// We need something that exists for calling statfs().
char target_fs[strlen(target_filename)+1];
char* slash = strchr(target_filename+1, '/');
if (slash != NULL) {
int count = slash - target_filename;
strncpy(target_fs, target_filename, count);
target_fs[count] = '\0';
} else {
strcpy(target_fs, target_filename);
}
do {
// Is there enough room in the target filesystem to hold the patched
// file?
if (strncmp(target_filename, "MTD:", 4) == 0 ||
strncmp(target_filename, "EMMC:", 5) == 0) {
// If the target is a partition, we're actually going to
// write the output to /tmp and then copy it to the
// partition. statfs() always returns 0 blocks free for
// /tmp, so instead we'll just assume that /tmp has enough
// space to hold the file.
// We still write the original source to cache, in case
// the partition write is interrupted.
if (MakeFreeSpaceOnCache(source_file.size) < 0) {
printf("not enough free space on /cache\n");
return 1;
}
if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
printf("failed to back up source file\n");
return 1;
}
made_copy = 1;
retry = 0;
} else {
int enough_space = 0;
if (retry > 0) {
size_t free_space = FreeSpaceForFile(target_fs);
enough_space =
(free_space > (256 << 10)) && // 256k (two-block) minimum
(free_space > (target_size * 3 / 2)); // 50% margin of error
printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
(long)target_size, (long)free_space, retry, enough_space);
}
if (!enough_space) {
retry = 0;
}
if (!enough_space && source_patch_value != NULL) {
// Using the original source, but not enough free space. First
// copy the source file to cache, then delete it from the original
// location.
if (strncmp(source_filename, "MTD:", 4) == 0 ||
strncmp(source_filename, "EMMC:", 5) == 0) {
// It's impossible to free space on the target filesystem by
// deleting the source if the source is a partition. If
// we're ever in a state where we need to do this, fail.
printf("not enough free space for target but source "
"is partition\n");
return 1;
}
if (MakeFreeSpaceOnCache(source_file.size) < 0) {
printf("not enough free space on /cache\n");
return 1;
}
if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
printf("failed to back up source file\n");
return 1;
}
made_copy = 1;
unlink(source_filename);
size_t free_space = FreeSpaceForFile(target_fs);
printf("(now %ld bytes free for target)\n", (long)free_space);
}
}
const Value* patch;
if (source_patch_value != NULL) {
source_to_use = &source_file;
patch = source_patch_value;
} else {
source_to_use = &copy_file;
patch = copy_patch_value;
}
if (patch->type != VAL_BLOB) {
printf("patch is not a blob\n");
return 1;
}
SinkFn sink = NULL;
void* token = NULL;
output = -1;
outname = NULL;
if (strncmp(target_filename, "MTD:", 4) == 0 ||
strncmp(target_filename, "EMMC:", 5) == 0) {
// We store the decoded output in memory.
msi.buffer = malloc(target_size);
if (msi.buffer == NULL) {
printf("failed to alloc %ld bytes for output\n",
(long)target_size);
return 1;
}
msi.pos = 0;
msi.size = target_size;
sink = MemorySink;
token = &msi;
} else {
// We write the decoded output to "<tgt-file>.patch".
outname = (char*)malloc(strlen(target_filename) + 10);
strcpy(outname, target_filename);
strcat(outname, ".patch");
output = open(outname, O_WRONLY | O_CREAT | O_TRUNC);
if (output < 0) {
printf("failed to open output file %s: %s\n",
outname, strerror(errno));
return 1;
}
sink = FileSink;
token = &output;
}
char* header = patch->data;
ssize_t header_bytes_read = patch->size;
SHA_init(&ctx);
int result;
if (header_bytes_read >= 8 &&
memcmp(header, "BSDIFF40", 8) == 0) {
result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
patch, 0, sink, token, &ctx);
} else if (header_bytes_read >= 8 &&
memcmp(header, "IMGDIFF2", 8) == 0) {
result = ApplyImagePatch(source_to_use->data, source_to_use->size,
patch, sink, token, &ctx);
} else {
printf("Unknown patch file format\n");
return 1;
}
if (output >= 0) {
fsync(output);
close(output);
}
if (result != 0) {
if (retry == 0) {
printf("applying patch failed\n");
return result != 0;
} else {
printf("applying patch failed; retrying\n");
}
if (outname != NULL) {
unlink(outname);
}
} else {
// succeeded; no need to retry
break;
}
} while (retry-- > 0);
const uint8_t* current_target_sha1 = SHA_final(&ctx);
if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
printf("patch did not produce expected sha1\n");
return 1;
}
if (output < 0) {
// Copy the temp file to the partition.
if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) {
printf("write of patched data to %s failed\n", target_filename);
return 1;
}
free(msi.buffer);
} else {
// Give the .patch file the same owner, group, and mode of the
// original source file.
if (chmod(outname, source_to_use->st.st_mode) != 0) {
printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno));
return 1;
}
if (chown(outname, source_to_use->st.st_uid,
source_to_use->st.st_gid) != 0) {
printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
return 1;
}
// Finally, rename the .patch file to replace the target file.
if (rename(outname, target_filename) != 0) {
printf("rename of .patch to \"%s\" failed: %s\n",
target_filename, strerror(errno));
return 1;
}
}
// If this run of applypatch created the copy, and we're here, we
// can delete it.
if (made_copy) unlink(CACHE_TEMP_SOURCE);
// Success!
return 0;
}

87
applypatch/applypatch.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _APPLYPATCH_H
#define _APPLYPATCH_H
#include <sys/stat.h>
#include "mincrypt/sha.h"
#include "minelf/Retouch.h"
#include "edify/expr.h"
typedef struct _Patch {
uint8_t sha1[SHA_DIGEST_SIZE];
const char* patch_filename;
} Patch;
typedef struct _FileContents {
uint8_t sha1[SHA_DIGEST_SIZE];
unsigned char* data;
ssize_t size;
struct stat st;
} FileContents;
// When there isn't enough room on the target filesystem to hold the
// patched version of the file, we copy the original here and delete
// it to free up space. If the expected source file doesn't exist, or
// is corrupted, we look to see if this file contains the bits we want
// and use it as the source instead.
#define CACHE_TEMP_SOURCE "/cache/saved.file"
typedef ssize_t (*SinkFn)(unsigned char*, ssize_t, void*);
// applypatch.c
int ShowLicenses();
size_t FreeSpaceForFile(const char* filename);
int CacheSizeCheck(size_t bytes);
int ParseSha1(const char* str, uint8_t* digest);
int applypatch(const char* source_filename,
const char* target_filename,
const char* target_sha1_str,
size_t target_size,
int num_patches,
char** const patch_sha1_str,
Value** patch_data);
int applypatch_check(const char* filename,
int num_patches,
char** const patch_sha1_str);
int LoadFileContents(const char* filename, FileContents* file,
int retouch_flag);
int SaveFileContents(const char* filename, FileContents file);
void FreeFileContents(FileContents* file);
int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
int num_patches);
// bsdiff.c
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx);
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
unsigned char** new_data, ssize_t* new_size);
// imgpatch.c
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx);
// freecache.c
int MakeFreeSpaceOnCache(size_t bytes_needed);
#endif

350
applypatch/applypatch.sh Executable file
View File

@ -0,0 +1,350 @@
#!/bin/bash
#
# A test suite for applypatch. Run in a client where you have done
# envsetup, choosecombo, etc.
#
# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your
# system partition.
#
#
# TODO: find some way to get this run regularly along with the rest of
# the tests.
EMULATOR_PORT=5580
DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata
# This must be the filename that applypatch uses for its copies.
CACHE_TEMP_SOURCE=/cache/saved.file
# Put all binaries and files here. We use /cache because it's a
# temporary filesystem in the emulator; it's created fresh each time
# the emulator starts.
WORK_DIR=/system
# partition that WORK_DIR is located on, without the leading slash
WORK_FS=system
# set to 0 to use a device instead
USE_EMULATOR=1
# ------------------------
tmpdir=$(mktemp -d)
if [ "$USE_EMULATOR" == 1 ]; then
emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
pid_emulator=$!
ADB="adb -s emulator-$EMULATOR_PORT "
else
ADB="adb -d "
fi
echo "waiting to connect to device"
$ADB wait-for-device
echo "device is available"
$ADB remount
# free up enough space on the system partition for the test to run.
$ADB shell rm -r /system/media
# run a command on the device; exit with the exit status of the device
# command.
run_command() {
$ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
}
testname() {
echo
echo "$1"...
testname="$1"
}
fail() {
echo
echo FAIL: $testname
echo
[ "$open_pid" == "" ] || kill $open_pid
[ "$pid_emulator" == "" ] || kill $pid_emulator
exit 1
}
sha1() {
sha1sum $1 | awk '{print $1}'
}
free_space() {
run_command df | awk "/$1/ {print gensub(/K/, \"\", \"g\", \$6)}"
}
cleanup() {
# not necessary if we're about to kill the emulator, but nice for
# running on real devices or already-running emulators.
testname "removing test files"
run_command rm $WORK_DIR/bloat.dat
run_command rm $WORK_DIR/old.file
run_command rm $WORK_DIR/foo
run_command rm $WORK_DIR/patch.bsdiff
run_command rm $WORK_DIR/applypatch
run_command rm $CACHE_TEMP_SOURCE
run_command rm /cache/bloat*.dat
[ "$pid_emulator" == "" ] || kill $pid_emulator
if [ $# == 0 ]; then
rm -rf $tmpdir
fi
}
cleanup leave_tmp
$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
BAD1_SHA1=$(printf "%040x" $RANDOM)
BAD2_SHA1=$(printf "%040x" $RANDOM)
OLD_SHA1=$(sha1 $DATA_DIR/old.file)
NEW_SHA1=$(sha1 $DATA_DIR/new.file)
NEW_SIZE=$(stat -c %s $DATA_DIR/new.file)
# --------------- basic execution ----------------------
testname "usage message"
run_command $WORK_DIR/applypatch && fail
testname "display license"
run_command $WORK_DIR/applypatch -l | grep -q -i copyright || fail
# --------------- check mode ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
testname "check mode single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "check mode cache (corrupted) single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode cache (corrupted) multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode cache (corrupted) failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
# remove the old file entirely
run_command rm $WORK_DIR/old.file
testname "check mode cache (missing) single"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
testname "check mode cache (missing) multiple"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
testname "check mode cache (missing) failure"
run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
# --------------- apply patch ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
echo hello > $tmpdir/foo
$ADB push $tmpdir/foo $WORK_DIR
# Check that the partition has enough space to apply the patch without
# copying. If it doesn't, we'll be testing the low-space condition
# when we intend to test the not-low-space condition.
testname "apply patches (with enough space)"
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS."
if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then
echo "Not enough space on /$WORK_FS to patch test file."
echo
echo "This doesn't mean that applypatch is necessarily broken;"
echo "just that /$WORK_FS doesn't have enough free space to"
echo "properly run this test."
exit 1
fi
testname "apply bsdiff patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- apply patch in new location ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
# Check that the partition has enough space to apply the patch without
# copying. If it doesn't, we'll be testing the low-space condition
# when we intend to test the not-low-space condition.
testname "apply patch to new location (with enough space)"
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS."
if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then
echo "Not enough space on /$WORK_FS to patch test file."
echo
echo "This doesn't mean that applypatch is necessarily broken;"
echo "just that /$WORK_FS doesn't have enough free space to"
echo "properly run this test."
exit 1
fi
run_command rm $WORK_DIR/new.file
run_command rm $CACHE_TEMP_SOURCE
testname "apply bsdiff patch to new location"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/new.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch to new location"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/new.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "apply bsdiff patch to new location with corrupted source"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo || fail
$ADB pull $WORK_DIR/new.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# put some junk in the cache copy, too
run_command dd if=/dev/urandom of=$CACHE_TEMP_SOURCE count=100 bs=1024 || fail
run_command rm $WORK_DIR/new.file
testname "apply bsdiff patch to new location with corrupted source and copy (no new file)"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo && fail
# put some junk in the new file
run_command dd if=/dev/urandom of=$WORK_DIR/new.file count=100 bs=1024 || fail
testname "apply bsdiff patch to new location with corrupted source and copy (bad new file)"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo && fail
# --------------- apply patch with low space on /system ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS; we'll soon fix that."
echo run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS now."
testname "apply bsdiff patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
testname "reapply bsdiff patch with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- apply patch with low space on /system and /cache ----------------------
$ADB push $DATA_DIR/old.file $WORK_DIR
$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
free_kb=$(free_space $WORK_FS)
echo "${free_kb}kb free on /$WORK_FS"
run_command mkdir /cache/subdir
run_command 'echo > /cache/subdir/a.file'
run_command 'echo > /cache/a.file'
run_command mkdir /cache/recovery /cache/recovery/otatest
run_command 'echo > /cache/recovery/otatest/b.file'
run_command "echo > $CACHE_TEMP_SOURCE"
free_kb=$(free_space cache)
echo "${free_kb}kb free on /cache; we'll soon fix that."
run_command dd if=/dev/zero of=/cache/bloat_small.dat count=128 bs=1024 || fail
run_command dd if=/dev/zero of=/cache/bloat_large.dat count=$((free_kb-640)) bs=1024 || fail
free_kb=$(free_space cache)
echo "${free_kb}kb free on /cache now."
testname "apply bsdiff patch with low space, full cache, can't delete enough"
$ADB shell 'cat >> /cache/bloat_large.dat' & open_pid=$!
echo "open_pid is $open_pid"
# size check should fail even though it deletes some stuff
run_command $WORK_DIR/applypatch -s $NEW_SIZE && fail
run_command ls /cache/bloat_small.dat && fail # was deleted
run_command ls /cache/a.file && fail # was deleted
run_command ls /cache/recovery/otatest/b.file && fail # was deleted
run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open
run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
# should fail; not enough files can be deleted
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff && fail
run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open
run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
kill $open_pid # /cache/bloat_large.dat is no longer open
testname "apply bsdiff patch with low space, full cache, can delete enough"
# should succeed after deleting /cache/bloat_large.dat
run_command $WORK_DIR/applypatch -s $NEW_SIZE || fail
run_command ls /cache/bloat_large.dat && fail # was deleted
run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy
# should succeed
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir
run_command ls $CACHE_TEMP_SOURCE && fail # was deleted because patching overwrote it, then deleted it
# --------------- apply patch from cache ----------------------
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# put some junk in the old file
run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
testname "apply bsdiff patch from cache (corrupted source) with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE
# remove the old file entirely
run_command rm $WORK_DIR/old.file
testname "apply bsdiff patch from cache (missing source) with low space"
run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail
$ADB pull $WORK_DIR/old.file $tmpdir/patched
diff -q $DATA_DIR/new.file $tmpdir/patched || fail
# --------------- cleanup ----------------------
cleanup
echo
echo PASS
echo

410
applypatch/bsdiff.c Normal file
View File

@ -0,0 +1,410 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Most of this code comes from bsdiff.c from the bsdiff-4.3
* distribution, which is:
*/
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <bzlib.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MIN(x,y) (((x)<(y)) ? (x) : (y))
static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h)
{
off_t i,j,k,x,tmp,jj,kk;
if(len<16) {
for(k=start;k<start+len;k+=j) {
j=1;x=V[I[k]+h];
for(i=1;k+i<start+len;i++) {
if(V[I[k+i]+h]<x) {
x=V[I[k+i]+h];
j=0;
};
if(V[I[k+i]+h]==x) {
tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
j++;
};
};
for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
if(j==1) I[k]=-1;
};
return;
};
x=V[I[start+len/2]+h];
jj=0;kk=0;
for(i=start;i<start+len;i++) {
if(V[I[i]+h]<x) jj++;
if(V[I[i]+h]==x) kk++;
};
jj+=start;kk+=jj;
i=start;j=0;k=0;
while(i<jj) {
if(V[I[i]+h]<x) {
i++;
} else if(V[I[i]+h]==x) {
tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
j++;
} else {
tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
while(jj+j<kk) {
if(V[I[jj+j]+h]==x) {
j++;
} else {
tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
if(jj>start) split(I,V,start,jj-start,h);
for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
if(jj==kk-1) I[jj]=-1;
if(start+len>kk) split(I,V,kk,start+len-kk,h);
}
static void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize)
{
off_t buckets[256];
off_t i,h,len;
for(i=0;i<256;i++) buckets[i]=0;
for(i=0;i<oldsize;i++) buckets[old[i]]++;
for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
for(i=255;i>0;i--) buckets[i]=buckets[i-1];
buckets[0]=0;
for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
I[0]=oldsize;
for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
V[oldsize]=0;
for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
I[0]=-1;
for(h=1;I[0]!=-(oldsize+1);h+=h) {
len=0;
for(i=0;i<oldsize+1;) {
if(I[i]<0) {
len-=I[i];
i-=I[i];
} else {
if(len) I[i-len]=-len;
len=V[I[i]]+1-i;
split(I,V,i,len,h);
i+=len;
len=0;
};
};
if(len) I[i-len]=-len;
};
for(i=0;i<oldsize+1;i++) I[V[i]]=i;
}
static off_t matchlen(u_char *old,off_t oldsize,u_char *new,off_t newsize)
{
off_t i;
for(i=0;(i<oldsize)&&(i<newsize);i++)
if(old[i]!=new[i]) break;
return i;
}
static off_t search(off_t *I,u_char *old,off_t oldsize,
u_char *new,off_t newsize,off_t st,off_t en,off_t *pos)
{
off_t x,y;
if(en-st<2) {
x=matchlen(old+I[st],oldsize-I[st],new,newsize);
y=matchlen(old+I[en],oldsize-I[en],new,newsize);
if(x>y) {
*pos=I[st];
return x;
} else {
*pos=I[en];
return y;
}
};
x=st+(en-st)/2;
if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) {
return search(I,old,oldsize,new,newsize,x,en,pos);
} else {
return search(I,old,oldsize,new,newsize,st,x,pos);
};
}
static void offtout(off_t x,u_char *buf)
{
off_t y;
if(x<0) y=-x; else y=x;
buf[0]=y%256;y-=buf[0];
y=y/256;buf[1]=y%256;y-=buf[1];
y=y/256;buf[2]=y%256;y-=buf[2];
y=y/256;buf[3]=y%256;y-=buf[3];
y=y/256;buf[4]=y%256;y-=buf[4];
y=y/256;buf[5]=y%256;y-=buf[5];
y=y/256;buf[6]=y%256;y-=buf[6];
y=y/256;buf[7]=y%256;
if(x<0) buf[7]|=0x80;
}
// This is main() from bsdiff.c, with the following changes:
//
// - old, oldsize, new, newsize are arguments; we don't load this
// data from files. old and new are owned by the caller; we
// don't free them at the end.
//
// - the "I" block of memory is owned by the caller, who passes a
// pointer to *I, which can be NULL. This way if we call
// bsdiff() multiple times with the same 'old' data, we only do
// the qsufsort() step the first time.
//
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
const char* patch_filename)
{
int fd;
off_t *I;
off_t scan,pos,len;
off_t lastscan,lastpos,lastoffset;
off_t oldscore,scsc;
off_t s,Sf,lenf,Sb,lenb;
off_t overlap,Ss,lens;
off_t i;
off_t dblen,eblen;
u_char *db,*eb;
u_char buf[8];
u_char header[32];
FILE * pf;
BZFILE * pfbz2;
int bz2err;
if (*IP == NULL) {
off_t* V;
*IP = malloc((oldsize+1) * sizeof(off_t));
V = malloc((oldsize+1) * sizeof(off_t));
qsufsort(*IP, V, old, oldsize);
free(V);
}
I = *IP;
if(((db=malloc(newsize+1))==NULL) ||
((eb=malloc(newsize+1))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
/* Create the patch file */
if ((pf = fopen(patch_filename, "w")) == NULL)
err(1, "%s", patch_filename);
/* Header is
0 8 "BSDIFF40"
8 8 length of bzip2ed ctrl block
16 8 length of bzip2ed diff block
24 8 length of new file */
/* File is
0 32 Header
32 ?? Bzip2ed ctrl block
?? ?? Bzip2ed diff block
?? ?? Bzip2ed extra block */
memcpy(header,"BSDIFF40",8);
offtout(0, header + 8);
offtout(0, header + 16);
offtout(newsize, header + 24);
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
/* Compute the differences, writing ctrl as we go */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan<newsize) {
oldscore=0;
for(scsc=scan+=len;scan<newsize;scan++) {
len=search(I,old,oldsize,new+scan,newsize-scan,
0,oldsize,&pos);
for(;scsc<scan+len;scsc++)
if((scsc+lastoffset<oldsize) &&
(old[scsc+lastoffset] == new[scsc]))
oldscore++;
if(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffset<oldsize) &&
(old[scan+lastoffset] == new[scan]))
oldscore--;
};
if((len!=oldscore) || (scan==newsize)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
if(old[lastpos+i]==new[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
lenb=0;
if(scan<newsize) {
s=0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(old[pos-i]==new[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
if(lastscan+lenf>scan-lenb) {
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;i<overlap;i++) {
if(new[lastscan+lenf-overlap+i]==
old[lastpos+lenf-overlap+i]) s++;
if(new[scan-lenb+i]==
old[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
lenf+=lens-overlap;
lenb-=lens;
};
for(i=0;i<lenf;i++)
db[dblen+i]=new[lastscan+i]-old[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=new[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
offtout(lenf,buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((scan-lenb)-(lastscan+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((pos-lenb)-(lastpos+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed ctrl data */
if ((len = ftello(pf)) == -1)
err(1, "ftello");
offtout(len-32, header + 8);
/* Write compressed diff data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, db, dblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed diff data */
if ((newsize = ftello(pf)) == -1)
err(1, "ftello");
offtout(newsize - len, header + 16);
/* Write compressed extra data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, eb, eblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Seek to the beginning, write the header, and close the file */
if (fseeko(pf, 0, SEEK_SET))
err(1, "fseeko");
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
if (fclose(pf))
err(1, "fclose");
/* Free the memory we used */
free(db);
free(eb);
return 0;
}

252
applypatch/bspatch.c Normal file
View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// This file is a nearly line-for-line copy of bspatch.c from the
// bsdiff-4.3 distribution; the primary differences being how the
// input and output data are read and the error handling. Running
// applypatch with the -l option will display the bsdiff license
// notice.
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <bzlib.h>
#include "mincrypt/sha.h"
#include "applypatch.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
"\n"
"Copyright 2003-2005 Colin Percival\n"
"All rights reserved\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted providing that the following conditions\n"
"are met:\n"
"1. Redistributions of source code must retain the above copyright\n"
" notice, this list of conditions and the following disclaimer.\n"
"2. Redistributions in binary form must reproduce the above copyright\n"
" notice, this list of conditions and the following disclaimer in the\n"
" documentation and/or other materials provided with the distribution.\n"
"\n"
"THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
"IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
"ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
"DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
"OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
"HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
"STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
"IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
"POSSIBILITY OF SUCH DAMAGE.\n"
"\n------------------\n\n"
"This program uses Julian R Seward's \"libbzip2\" library, available\n"
"from http://www.bzip.org/.\n"
);
}
static off_t offtin(u_char *buf)
{
off_t y;
y=buf[7]&0x7F;
y=y*256;y+=buf[6];
y=y*256;y+=buf[5];
y=y*256;y+=buf[4];
y=y*256;y+=buf[3];
y=y*256;y+=buf[2];
y=y*256;y+=buf[1];
y=y*256;y+=buf[0];
if(buf[7]&0x80) y=-y;
return y;
}
int FillBuffer(unsigned char* buffer, int size, bz_stream* stream) {
stream->next_out = (char*)buffer;
stream->avail_out = size;
while (stream->avail_out > 0) {
int bzerr = BZ2_bzDecompress(stream);
if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) {
printf("bz error %d decompressing\n", bzerr);
return -1;
}
if (stream->avail_out > 0) {
printf("need %d more bytes\n", stream->avail_out);
}
}
return 0;
}
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx) {
unsigned char* new_data;
ssize_t new_size;
if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
&new_data, &new_size) != 0) {
return -1;
}
if (sink(new_data, new_size, token) < new_size) {
printf("short write of output: %d (%s)\n", errno, strerror(errno));
return 1;
}
if (ctx) {
SHA_update(ctx, new_data, new_size);
}
free(new_data);
return 0;
}
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
unsigned char** new_data, ssize_t* new_size) {
// Patch data format:
// 0 8 "BSDIFF40"
// 8 8 X
// 16 8 Y
// 24 8 sizeof(newfile)
// 32 X bzip2(control block)
// 32+X Y bzip2(diff block)
// 32+X+Y ??? bzip2(extra block)
// with control block a set of triples (x,y,z) meaning "add x bytes
// from oldfile to x bytes from the diff block; copy y bytes from the
// extra block; seek forwards in oldfile by z bytes".
unsigned char* header = (unsigned char*) patch->data + patch_offset;
if (memcmp(header, "BSDIFF40", 8) != 0) {
printf("corrupt bsdiff patch file header (magic number)\n");
return 1;
}
ssize_t ctrl_len, data_len;
ctrl_len = offtin(header+8);
data_len = offtin(header+16);
*new_size = offtin(header+24);
if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
printf("corrupt patch file header (data lengths)\n");
return 1;
}
int bzerr;
bz_stream cstream;
cstream.next_in = patch->data + patch_offset + 32;
cstream.avail_in = ctrl_len;
cstream.bzalloc = NULL;
cstream.bzfree = NULL;
cstream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) {
printf("failed to bzinit control stream (%d)\n", bzerr);
}
bz_stream dstream;
dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
dstream.avail_in = data_len;
dstream.bzalloc = NULL;
dstream.bzfree = NULL;
dstream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) {
printf("failed to bzinit diff stream (%d)\n", bzerr);
}
bz_stream estream;
estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
estream.bzalloc = NULL;
estream.bzfree = NULL;
estream.opaque = NULL;
if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) {
printf("failed to bzinit extra stream (%d)\n", bzerr);
}
*new_data = malloc(*new_size);
if (*new_data == NULL) {
printf("failed to allocate %ld bytes of memory for output file\n",
(long)*new_size);
return 1;
}
off_t oldpos = 0, newpos = 0;
off_t ctrl[3];
off_t len_read;
int i;
unsigned char buf[24];
while (newpos < *new_size) {
// Read control data
if (FillBuffer(buf, 24, &cstream) != 0) {
printf("error while reading control stream\n");
return 1;
}
ctrl[0] = offtin(buf);
ctrl[1] = offtin(buf+8);
ctrl[2] = offtin(buf+16);
// Sanity check
if (newpos + ctrl[0] > *new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read diff string
if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
printf("error while reading diff stream\n");
return 1;
}
// Add old data to diff string
for (i = 0; i < ctrl[0]; ++i) {
if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
(*new_data)[newpos+i] += old_data[oldpos+i];
}
}
// Adjust pointers
newpos += ctrl[0];
oldpos += ctrl[0];
// Sanity check
if (newpos + ctrl[1] > *new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read extra string
if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
printf("error while reading extra stream\n");
return 1;
}
// Adjust pointers
newpos += ctrl[1];
oldpos += ctrl[2];
}
BZ2_bzDecompressEnd(&cstream);
BZ2_bzDecompressEnd(&dstream);
BZ2_bzDecompressEnd(&estream);
return 0;
}

172
applypatch/freecache.c Normal file
View File

@ -0,0 +1,172 @@
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>
#include "applypatch.h"
static int EliminateOpenFiles(char** files, int file_count) {
DIR* d;
struct dirent* de;
d = opendir("/proc");
if (d == NULL) {
printf("error opening /proc: %s\n", strerror(errno));
return -1;
}
while ((de = readdir(d)) != 0) {
int i;
for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i);
if (de->d_name[i]) continue;
// de->d_name[i] is numeric
char path[FILENAME_MAX];
strcpy(path, "/proc/");
strcat(path, de->d_name);
strcat(path, "/fd/");
DIR* fdd;
struct dirent* fdde;
fdd = opendir(path);
if (fdd == NULL) {
printf("error opening %s: %s\n", path, strerror(errno));
continue;
}
while ((fdde = readdir(fdd)) != 0) {
char fd_path[FILENAME_MAX];
char link[FILENAME_MAX];
strcpy(fd_path, path);
strcat(fd_path, fdde->d_name);
int count;
count = readlink(fd_path, link, sizeof(link)-1);
if (count >= 0) {
link[count] = '\0';
// This is inefficient, but it should only matter if there are
// lots of files in /cache, and lots of them are open (neither
// of which should be true, especially in recovery).
if (strncmp(link, "/cache/", 7) == 0) {
int j;
for (j = 0; j < file_count; ++j) {
if (files[j] && strcmp(files[j], link) == 0) {
printf("%s is open by %s\n", link, de->d_name);
free(files[j]);
files[j] = NULL;
}
}
}
}
}
closedir(fdd);
}
closedir(d);
return 0;
}
int FindExpendableFiles(char*** names, int* entries) {
DIR* d;
struct dirent* de;
int size = 32;
*entries = 0;
*names = malloc(size * sizeof(char*));
char path[FILENAME_MAX];
// We're allowed to delete unopened regular files in any of these
// directories.
const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
unsigned int i;
for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
d = opendir(dirs[i]);
if (d == NULL) {
printf("error opening %s: %s\n", dirs[i], strerror(errno));
continue;
}
// Look for regular files in the directory (not in any subdirectories).
while ((de = readdir(d)) != 0) {
strcpy(path, dirs[i]);
strcat(path, "/");
strcat(path, de->d_name);
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
// restarted during installation and could be depending on it to
// be there.
if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue;
struct stat st;
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
if (*entries >= size) {
size *= 2;
*names = realloc(*names, size * sizeof(char*));
}
(*names)[(*entries)++] = strdup(path);
}
}
closedir(d);
}
printf("%d regular files in deletable directories\n", *entries);
if (EliminateOpenFiles(*names, *entries) < 0) {
return -1;
}
return 0;
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
size_t free_now = FreeSpaceForFile("/cache");
printf("%ld bytes free on /cache (%ld needed)\n",
(long)free_now, (long)bytes_needed);
if (free_now >= bytes_needed) {
return 0;
}
char** names;
int entries;
if (FindExpendableFiles(&names, &entries) < 0) {
return -1;
}
if (entries == 0) {
// nothing we can delete to free up space!
printf("no files can be deleted to free space on /cache\n");
return -1;
}
// We could try to be smarter about which files to delete: the
// biggest ones? the smallest ones that will free up enough space?
// the oldest? the newest?
//
// Instead, we'll be dumb.
int i;
for (i = 0; i < entries && free_now < bytes_needed; ++i) {
if (names[i]) {
unlink(names[i]);
free_now = FreeSpaceForFile("/cache");
printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now);
free(names[i]);
}
}
for (; i < entries; ++i) {
free(names[i]);
}
free(names);
return (free_now >= bytes_needed) ? 0 : -1;
}

1010
applypatch/imgdiff.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,11 +14,17 @@
* limitations under the License.
*/
#ifndef AMEND_PARSER_H_
#define AMEND_PARSER_H_
// Image patch chunk types
#define CHUNK_NORMAL 0
#define CHUNK_GZIP 1 // version 1 only
#define CHUNK_DEFLATE 2 // version 2 only
#define CHUNK_RAW 3 // version 2 only
#include "parser_y.h"
// The gzip header size is actually variable, but we currently don't
// support gzipped data with any of the optional fields, so for now it
// will always be ten bytes. See RFC 1952 for the definition of the
// gzip format.
#define GZIP_HEADER_LEN 10
int yyparse(void);
#endif // AMEND_PARSER_H_
// The gzip footer size really is fixed.
#define GZIP_FOOTER_LEN 8

118
applypatch/imgdiff_test.sh Executable file
View File

@ -0,0 +1,118 @@
#!/bin/bash
#
# A script for testing imgdiff/applypatch. It takes two full OTA
# packages as arguments. It generates (on the host) patches for all
# the zip/jar/apk files they have in common, as well as boot and
# recovery images. It then applies the patches on the device (or
# emulator) and checks that the resulting file is correct.
EMULATOR_PORT=5580
# set to 0 to use a device instead
USE_EMULATOR=0
# where on the device to do all the patching.
WORK_DIR=/data/local/tmp
START_OTA_PACKAGE=$1
END_OTA_PACKAGE=$2
# ------------------------
tmpdir=$(mktemp -d)
if [ "$USE_EMULATOR" == 1 ]; then
emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
pid_emulator=$!
ADB="adb -s emulator-$EMULATOR_PORT "
else
ADB="adb -d "
fi
echo "waiting to connect to device"
$ADB wait-for-device
# run a command on the device; exit with the exit status of the device
# command.
run_command() {
$ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
}
testname() {
echo
echo "$1"...
testname="$1"
}
fail() {
echo
echo FAIL: $testname
echo
[ "$open_pid" == "" ] || kill $open_pid
[ "$pid_emulator" == "" ] || kill $pid_emulator
exit 1
}
sha1() {
sha1sum $1 | awk '{print $1}'
}
size() {
stat -c %s $1 | tr -d '\n'
}
cleanup() {
# not necessary if we're about to kill the emulator, but nice for
# running on real devices or already-running emulators.
testname "removing test files"
run_command rm $WORK_DIR/applypatch
run_command rm $WORK_DIR/source
run_command rm $WORK_DIR/target
run_command rm $WORK_DIR/patch
[ "$pid_emulator" == "" ] || kill $pid_emulator
rm -rf $tmpdir
}
$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
patch_and_apply() {
local fn=$1
shift
unzip -p $START_OTA_PACKAGE $fn > $tmpdir/source
unzip -p $END_OTA_PACKAGE $fn > $tmpdir/target
imgdiff "$@" $tmpdir/source $tmpdir/target $tmpdir/patch
bsdiff $tmpdir/source $tmpdir/target $tmpdir/patch.bs
echo "patch for $fn is $(size $tmpdir/patch) [of $(size $tmpdir/target)] ($(size $tmpdir/patch.bs) with bsdiff)"
echo "$fn $(size $tmpdir/patch) of $(size $tmpdir/target) bsdiff $(size $tmpdir/patch.bs)" >> /tmp/stats.txt
$ADB push $tmpdir/source $WORK_DIR/source || fail "source push failed"
run_command rm /data/local/tmp/target
$ADB push $tmpdir/patch $WORK_DIR/patch || fail "patch push failed"
run_command /data/local/tmp/applypatch /data/local/tmp/source \
/data/local/tmp/target $(sha1 $tmpdir/target) $(size $tmpdir/target) \
$(sha1 $tmpdir/source):/data/local/tmp/patch \
|| fail "applypatch of $fn failed"
$ADB pull /data/local/tmp/target $tmpdir/result
diff -q $tmpdir/target $tmpdir/result || fail "patch output not correct!"
}
# --------------- basic execution ----------------------
for i in $((zipinfo -1 $START_OTA_PACKAGE; zipinfo -1 $END_OTA_PACKAGE) | \
sort | uniq -d | egrep -e '[.](apk|jar|zip)$'); do
patch_and_apply $i -z
done
patch_and_apply boot.img
patch_and_apply system/recovery.img
# --------------- cleanup ----------------------
cleanup
echo
echo PASS
echo

219
applypatch/imgpatch.c Normal file
View File

@ -0,0 +1,219 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// See imgdiff.c in this directory for a description of the patch file
// format.
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "zlib.h"
#include "mincrypt/sha.h"
#include "applypatch.h"
#include "imgdiff.h"
#include "utils.h"
/*
* Apply the patch given in 'patch_filename' to the source data given
* by (old_data, old_size). Write the patched output to the 'output'
* file, and update the SHA context with the output data as well.
* Return 0 on success.
*/
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx) {
ssize_t pos = 12;
char* header = patch->data;
if (patch->size < 12) {
printf("patch too short to contain header\n");
return -1;
}
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
// (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
// CHUNK_GZIP.)
if (memcmp(header, "IMGDIFF2", 8) != 0) {
printf("corrupt patch file header (magic number)\n");
return -1;
}
int num_chunks = Read4(header+8);
int i;
for (i = 0; i < num_chunks; ++i) {
// each chunk's header record starts with 4 bytes.
if (pos + 4 > patch->size) {
printf("failed to read chunk %d record\n", i);
return -1;
}
int type = Read4(patch->data + pos);
pos += 4;
if (type == CHUNK_NORMAL) {
char* normal_header = patch->data + pos;
pos += 24;
if (pos > patch->size) {
printf("failed to read chunk %d normal header data\n", i);
return -1;
}
size_t src_start = Read8(normal_header);
size_t src_len = Read8(normal_header+8);
size_t patch_offset = Read8(normal_header+16);
ApplyBSDiffPatch(old_data + src_start, src_len,
patch, patch_offset, sink, token, ctx);
} else if (type == CHUNK_RAW) {
char* raw_header = patch->data + pos;
pos += 4;
if (pos > patch->size) {
printf("failed to read chunk %d raw header data\n", i);
return -1;
}
ssize_t data_len = Read4(raw_header);
if (pos + data_len > patch->size) {
printf("failed to read chunk %d raw data\n", i);
return -1;
}
SHA_update(ctx, patch->data + pos, data_len);
if (sink((unsigned char*)patch->data + pos,
data_len, token) != data_len) {
printf("failed to write chunk %d raw data\n", i);
return -1;
}
pos += data_len;
} else if (type == CHUNK_DEFLATE) {
// deflate chunks have an additional 60 bytes in their chunk header.
char* deflate_header = patch->data + pos;
pos += 60;
if (pos > patch->size) {
printf("failed to read chunk %d deflate header data\n", i);
return -1;
}
size_t src_start = Read8(deflate_header);
size_t src_len = Read8(deflate_header+8);
size_t patch_offset = Read8(deflate_header+16);
size_t expanded_len = Read8(deflate_header+24);
size_t target_len = Read8(deflate_header+32);
int level = Read4(deflate_header+40);
int method = Read4(deflate_header+44);
int windowBits = Read4(deflate_header+48);
int memLevel = Read4(deflate_header+52);
int strategy = Read4(deflate_header+56);
// Decompress the source data; the chunk header tells us exactly
// how big we expect it to be when decompressed.
unsigned char* expanded_source = malloc(expanded_len);
if (expanded_source == NULL) {
printf("failed to allocate %d bytes for expanded_source\n",
expanded_len);
return -1;
}
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = src_len;
strm.next_in = (unsigned char*)(old_data + src_start);
strm.avail_out = expanded_len;
strm.next_out = expanded_source;
int ret;
ret = inflateInit2(&strm, -15);
if (ret != Z_OK) {
printf("failed to init source inflation: %d\n", ret);
return -1;
}
// Because we've provided enough room to accommodate the output
// data, we expect one call to inflate() to suffice.
ret = inflate(&strm, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END) {
printf("source inflation returned %d\n", ret);
return -1;
}
// We should have filled the output buffer exactly.
if (strm.avail_out != 0) {
printf("source inflation short by %d bytes\n", strm.avail_out);
return -1;
}
inflateEnd(&strm);
// Next, apply the bsdiff patch (in memory) to the uncompressed
// data.
unsigned char* uncompressed_target_data;
ssize_t uncompressed_target_size;
if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
patch, patch_offset,
&uncompressed_target_data,
&uncompressed_target_size) != 0) {
return -1;
}
// Now compress the target data and append it to the output.
// we're done with the expanded_source data buffer, so we'll
// reuse that memory to receive the output of deflate.
unsigned char* temp_data = expanded_source;
ssize_t temp_size = expanded_len;
if (temp_size < 32768) {
// ... unless the buffer is too small, in which case we'll
// allocate a fresh one.
free(temp_data);
temp_data = malloc(32768);
temp_size = 32768;
}
// now the deflate stream
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = uncompressed_target_size;
strm.next_in = uncompressed_target_data;
ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
do {
strm.avail_out = temp_size;
strm.next_out = temp_data;
ret = deflate(&strm, Z_FINISH);
ssize_t have = temp_size - strm.avail_out;
if (sink(temp_data, have, token) != have) {
printf("failed to write %ld compressed bytes to output\n",
(long)have);
return -1;
}
SHA_update(ctx, temp_data, have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
free(temp_data);
free(uncompressed_target_data);
} else {
printf("patch chunk %d is unknown type %d\n", i, type);
return -1;
}
}
return 0;
}

195
applypatch/main.c Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "applypatch.h"
#include "edify/expr.h"
#include "mincrypt/sha.h"
int CheckMode(int argc, char** argv) {
if (argc < 3) {
return 2;
}
return applypatch_check(argv[2], argc-3, argv+3);
}
int SpaceMode(int argc, char** argv) {
if (argc != 3) {
return 2;
}
char* endptr;
size_t bytes = strtol(argv[2], &endptr, 10);
if (bytes == 0 && endptr == argv[2]) {
printf("can't parse \"%s\" as byte count\n\n", argv[2]);
return 1;
}
return CacheSizeCheck(bytes);
}
// Parse arguments (which should be of the form "<sha1>" or
// "<sha1>:<filename>" into the new parallel arrays *sha1s and
// *patches (loading file contents into the patches). Returns 0 on
// success.
static int ParsePatchArgs(int argc, char** argv,
char*** sha1s, Value*** patches, int* num_patches) {
*num_patches = argc;
*sha1s = malloc(*num_patches * sizeof(char*));
*patches = malloc(*num_patches * sizeof(Value*));
memset(*patches, 0, *num_patches * sizeof(Value*));
uint8_t digest[SHA_DIGEST_SIZE];
int i;
for (i = 0; i < *num_patches; ++i) {
char* colon = strchr(argv[i], ':');
if (colon != NULL) {
*colon = '\0';
++colon;
}
if (ParseSha1(argv[i], digest) != 0) {
printf("failed to parse sha1 \"%s\"\n", argv[i]);
return -1;
}
(*sha1s)[i] = argv[i];
if (colon == NULL) {
(*patches)[i] = NULL;
} else {
FileContents fc;
if (LoadFileContents(colon, &fc, RETOUCH_DONT_MASK) != 0) {
goto abort;
}
(*patches)[i] = malloc(sizeof(Value));
(*patches)[i]->type = VAL_BLOB;
(*patches)[i]->size = fc.size;
(*patches)[i]->data = (char*)fc.data;
}
}
return 0;
abort:
for (i = 0; i < *num_patches; ++i) {
Value* p = (*patches)[i];
if (p != NULL) {
free(p->data);
free(p);
}
}
free(*sha1s);
free(*patches);
return -1;
}
int PatchMode(int argc, char** argv) {
if (argc < 6) {
return 2;
}
char* endptr;
size_t target_size = strtol(argv[4], &endptr, 10);
if (target_size == 0 && endptr == argv[4]) {
printf("can't parse \"%s\" as byte count\n\n", argv[4]);
return 1;
}
char** sha1s;
Value** patches;
int num_patches;
if (ParsePatchArgs(argc-5, argv+5, &sha1s, &patches, &num_patches) != 0) {
printf("failed to parse patch args\n");
return 1;
}
int result = applypatch(argv[1], argv[2], argv[3], target_size,
num_patches, sha1s, patches);
int i;
for (i = 0; i < num_patches; ++i) {
Value* p = patches[i];
if (p != NULL) {
free(p->data);
free(p);
}
}
free(sha1s);
free(patches);
return result;
}
// This program applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
// multiple times).
//
// - if the sha1 hash of <tgt-file> is <tgt-sha1>, does nothing and exits
// successfully.
//
// - otherwise, if the sha1 hash of <src-file> is <src-sha1>, applies the
// bsdiff <patch> to <src-file> to produce a new file (the type of patch
// is automatically detected from the file header). If that new
// file has sha1 hash <tgt-sha1>, moves it to replace <tgt-file>, and
// exits successfully. Note that if <src-file> and <tgt-file> are
// not the same, <src-file> is NOT deleted on success. <tgt-file>
// may be the string "-" to mean "the same as src-file".
//
// - otherwise, or if any error is encountered, exits with non-zero
// status.
//
// <src-file> (or <file> in check mode) may refer to an MTD partition
// to read the source data. See the comments for the
// LoadMTDContents() function above for the format of such a filename.
int main(int argc, char** argv) {
if (argc < 2) {
usage:
printf(
"usage: %s <src-file> <tgt-file> <tgt-sha1> <tgt-size> "
"[<src-sha1>:<patch> ...]\n"
" or %s -c <file> [<sha1> ...]\n"
" or %s -s <bytes>\n"
" or %s -l\n"
"\n"
"Filenames may be of the form\n"
" MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
"to specify reading from or writing to an MTD partition.\n\n",
argv[0], argv[0], argv[0], argv[0]);
return 2;
}
int result;
if (strncmp(argv[1], "-l", 3) == 0) {
result = ShowLicenses();
} else if (strncmp(argv[1], "-c", 3) == 0) {
result = CheckMode(argc, argv);
} else if (strncmp(argv[1], "-s", 3) == 0) {
result = SpaceMode(argc, argv);
} else {
result = PatchMode(argc, argv);
}
if (result == 2) {
goto usage;
}
return result;
}

BIN
applypatch/testdata/new.file vendored Normal file

Binary file not shown.

BIN
applypatch/testdata/old.file vendored Normal file

Binary file not shown.

BIN
applypatch/testdata/patch.bsdiff vendored Normal file

Binary file not shown.

65
applypatch/utils.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "utils.h"
/** Write a 4-byte value to f in little-endian order. */
void Write4(int value, FILE* f) {
fputc(value & 0xff, f);
fputc((value >> 8) & 0xff, f);
fputc((value >> 16) & 0xff, f);
fputc((value >> 24) & 0xff, f);
}
/** Write an 8-byte value to f in little-endian order. */
void Write8(long long value, FILE* f) {
fputc(value & 0xff, f);
fputc((value >> 8) & 0xff, f);
fputc((value >> 16) & 0xff, f);
fputc((value >> 24) & 0xff, f);
fputc((value >> 32) & 0xff, f);
fputc((value >> 40) & 0xff, f);
fputc((value >> 48) & 0xff, f);
fputc((value >> 56) & 0xff, f);
}
int Read2(void* pv) {
unsigned char* p = pv;
return (int)(((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
int Read4(void* pv) {
unsigned char* p = pv;
return (int)(((unsigned int)p[3] << 24) |
((unsigned int)p[2] << 16) |
((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
long long Read8(void* pv) {
unsigned char* p = pv;
return (long long)(((unsigned long long)p[7] << 56) |
((unsigned long long)p[6] << 48) |
((unsigned long long)p[5] << 40) |
((unsigned long long)p[4] << 32) |
((unsigned long long)p[3] << 24) |
((unsigned long long)p[2] << 16) |
((unsigned long long)p[1] << 8) |
(unsigned long long)p[0]);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007 The Android Open Source Project
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,15 +14,17 @@
* limitations under the License.
*/
#ifndef RECOVERY_COMMANDS_H_
#define RECOVERY_COMMANDS_H_
#ifndef _BUILD_TOOLS_APPLYPATCH_UTILS_H
#define _BUILD_TOOLS_APPLYPATCH_UTILS_H
#include "minzip/Zip.h"
#include <stdio.h>
typedef struct {
ZipArchive *package;
} RecoveryCommandContext;
// Read and write little-endian values of various sizes.
int register_update_commands(RecoveryCommandContext *ctx);
void Write4(int value, FILE* f);
void Write8(long long value, FILE* f);
int Read2(void* p);
int Read4(void* p);
long long Read8(void* p);
#endif // RECOVERY_COMMANDS_H_
#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H

19
bmlutils/Android.mk Normal file
View File

@ -0,0 +1,19 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
BOARD_RECOVERY_DEFINES := BOARD_BML_BOOT BOARD_BML_RECOVERY
$(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
$(if $($(board_define)), \
$(eval LOCAL_CFLAGS += -D$(board_define)=\"$($(board_define))\") \
) \
)
LOCAL_STATIC_LIBRARIES := libcrecovery
LOCAL_C_INCLUDES := bootable/recovery/libcrecovery
LOCAL_SRC_FILES := bmlutils.c
LOCAL_MODULE := libbmlutils
LOCAL_MODULE_TAGS := eng
include $(BUILD_STATIC_LIBRARY)

206
bmlutils/bmlutils.c Normal file
View File

@ -0,0 +1,206 @@
#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 <common.h>
#define BML_UNLOCK_ALL 0x8A29 ///< unlock all partition RO -> RW
#ifndef BOARD_BML_BOOT
#define BOARD_BML_BOOT "/dev/block/bml7"
#endif
#ifndef BOARD_BML_RECOVERY
#define BOARD_BML_RECOVERY "/dev/block/bml8"
#endif
static int restore_internal(const char* bml, const char* filename)
{
char buf[4096];
int dstfd, srcfd, bytes_read, bytes_written, total_read = 0;
if (filename == NULL)
srcfd = 0;
else {
srcfd = open(filename, O_RDONLY | O_LARGEFILE);
if (srcfd < 0)
return 2;
}
dstfd = open(bml, O_RDWR | O_LARGEFILE);
if (dstfd < 0)
return 3;
if (ioctl(dstfd, BML_UNLOCK_ALL, 0))
return 4;
do {
total_read += bytes_read = read(srcfd, buf, 4096);
if (!bytes_read)
break;
if (bytes_read < 4096)
memset(&buf[bytes_read], 0, 4096 - bytes_read);
if (write(dstfd, buf, 4096) < 4096)
return 5;
} while(bytes_read == 4096);
close(dstfd);
close(srcfd);
return 0;
}
int cmd_bml_restore_raw_partition(const char *partition, const char *filename)
{
if (strcmp(partition, "boot") != 0 && strcmp(partition, "recovery") != 0 && strcmp(partition, "recoveryonly") != 0 && partition[0] != '/')
return 6;
int ret = -1;
if (strcmp(partition, "recoveryonly") != 0) {
// always restore boot, regardless of whether recovery or boot is flashed.
// this is because boot and recovery are the same on some samsung phones.
// unless of course, recoveryonly is explictly chosen (bml8)
ret = restore_internal(BOARD_BML_BOOT, filename);
if (ret != 0)
return ret;
}
if (strcmp(partition, "recovery") == 0 || strcmp(partition, "recoveryonly") == 0)
ret = restore_internal(BOARD_BML_RECOVERY, filename);
// support explicitly provided device paths
if (partition[0] == '/')
ret = restore_internal(partition, filename);
return ret;
}
int cmd_bml_backup_raw_partition(const char *partition, const char *out_file)
{
char* bml;
if (strcmp("boot", partition) == 0)
bml = BOARD_BML_BOOT;
else if (strcmp("recovery", partition) == 0)
bml = BOARD_BML_RECOVERY;
else if (partition[0] == '/') {
// support explicitly provided device paths
bml = partition;
}
else {
printf("Invalid partition.\n");
return -1;
}
int ch;
FILE *in;
FILE *out;
int val = 0;
char buf[512];
unsigned sz = 0;
unsigned i;
int ret = -1;
char *in_file = bml;
in = fopen ( in_file, "r" );
if (in == NULL)
goto ERROR3;
out = fopen ( out_file, "w" );
if (out == NULL)
goto ERROR2;
fseek(in, 0L, SEEK_END);
sz = ftell(in);
fseek(in, 0L, SEEK_SET);
if (sz % 512)
{
while ( ( ch = fgetc ( in ) ) != EOF )
fputc ( ch, out );
}
else
{
for (i=0; i< (sz/512); i++)
{
if ((fread(buf, 512, 1, in)) != 1)
goto ERROR1;
if ((fwrite(buf, 512, 1, out)) != 1)
goto ERROR1;
}
}
fsync(out);
ret = 0;
ERROR1:
fclose ( out );
ERROR2:
fclose ( in );
ERROR3:
return ret;
}
int cmd_bml_erase_raw_partition(const char *partition)
{
// TODO: implement raw wipe
return 0;
}
int cmd_bml_erase_partition(const char *partition, const char *filesystem)
{
return -1;
}
int cmd_bml_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
{
return -1;
}
int cmd_bml_get_partition_device(const char *partition, char *device)
{
return -1;
}
int format_rfs_device (const char *device, const char *path) {
const char *fatsize = "32";
const char *sectorsize = "1";
if (strcmp(path, "/datadata") == 0 || strcmp(path, "/cache") == 0) {
fatsize = "16";
}
// Just in case /data sector size needs to be altered
else if (strcmp(path, "/data") == 0 ) {
sectorsize = "1";
}
// dump 10KB of zeros to partition before format due to fat.format bug
char cmd[PATH_MAX];
sprintf(cmd, "/sbin/dd if=/dev/zero of=%s bs=4096 count=10", device);
if(__system(cmd)) {
printf("failure while zeroing rfs partition.\n");
return -1;
}
// Run fat.format
sprintf(cmd, "/sbin/fat.format -F %s -S 4096 -s %s %s", fatsize, sectorsize, device);
if(__system(cmd)) {
printf("failure while running fat.format\n");
return -1;
}
return 0;
}

6
bmlutils/bmlutils.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef BMLUTILS_H_
#define BMLUTILS_H_
int format_rfs_device (const char *device, const char *path);
#endif // BMLUTILS_H_

View File

@ -22,97 +22,114 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
int get_bootloader_message(struct bootloader_message *out) {
Volume* v = volume_for_path("/misc");
if(v)
{
if (strcmp(v->fs_type, "mtd") == 0) {
return get_bootloader_message_mtd(out, v);
} else if (strcmp(v->fs_type, "emmc") == 0) {
return get_bootloader_message_block(out, v);
}
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
return -1;
}
return -1;
}
int set_bootloader_message(const struct bootloader_message *in) {
Volume* v = volume_for_path("/misc");
if(v)
{
if (strcmp(v->fs_type, "mtd") == 0) {
return set_bootloader_message_mtd(in, v);
} else if (strcmp(v->fs_type, "emmc") == 0) {
return set_bootloader_message_block(in, v);
}
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
return -1;
}
return -1;
}
// ------------------------------
// for misc partitions on MTD
// ------------------------------
static const char *CACHE_NAME = "CACHE:";
static const char *MISC_NAME = "MISC:";
static const int MISC_PAGES = 3; // number of pages to save
static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
#ifdef LOG_VERBOSE
static void dump_data(const char *data, int len) {
int pos;
for (pos = 0; pos < len; ) {
printf("%05x: %02x", pos, data[pos]);
for (++pos; pos < len && (pos % 24) != 0; ++pos) {
printf(" %02x", data[pos]);
}
printf("\n");
}
}
#endif
int get_bootloader_message(struct bootloader_message *out) {
static int get_bootloader_message_mtd(struct bootloader_message *out,
const Volume* v) {
size_t write_size;
const MtdPartition *part = get_root_mtd_partition(MISC_NAME);
mtd_scan_partitions();
const MtdPartition *part = mtd_find_partition_by_name(v->device);
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
LOGE("Can't find %s\n", MISC_NAME);
LOGE("Can't find %s\n", v->device);
return -1;
}
MtdReadContext *read = mtd_read_partition(part);
if (read == NULL) {
LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
const ssize_t size = write_size * MISC_PAGES;
char data[size];
ssize_t r = mtd_read_data(read, data, size);
if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
#ifdef LOG_VERBOSE
printf("\n--- get_bootloader_message ---\n");
dump_data(data, size);
printf("\n");
#endif
memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
return 0;
}
int set_bootloader_message(const struct bootloader_message *in) {
static int set_bootloader_message_mtd(const struct bootloader_message *in,
const Volume* v) {
size_t write_size;
const MtdPartition *part = get_root_mtd_partition(MISC_NAME);
mtd_scan_partitions();
const MtdPartition *part = mtd_find_partition_by_name(v->device);
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
LOGE("Can't find %s\n", MISC_NAME);
LOGE("Can't find %s\n", v->device);
return -1;
}
MtdReadContext *read = mtd_read_partition(part);
if (read == NULL) {
LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
ssize_t size = write_size * MISC_PAGES;
char data[size];
ssize_t r = mtd_read_data(read, data, size);
if (r != size) LOGE("Can't read %s\n(%s)\n", MISC_NAME, strerror(errno));
if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
#ifdef LOG_VERBOSE
printf("\n--- set_bootloader_message ---\n");
dump_data(data, size);
printf("\n");
#endif
MtdWriteContext *write = mtd_write_partition(part);
if (write == NULL) {
LOGE("Can't open %s\n(%s)\n", MISC_NAME, strerror(errno));
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
if (mtd_write_data(write, data, size) != size) {
LOGE("Can't write %s\n(%s)\n", MISC_NAME, strerror(errno));
LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno));
mtd_write_close(write);
return -1;
}
if (mtd_write_close(write)) {
LOGE("Can't finish %s\n(%s)\n", MISC_NAME, strerror(errno));
LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
@ -120,6 +137,70 @@ int set_bootloader_message(const struct bootloader_message *in) {
return 0;
}
// ------------------------------------
// for misc partitions on block devices
// ------------------------------------
static void wait_for_device(const char* fn) {
int tries = 0;
int ret;
struct stat buf;
do {
++tries;
ret = stat(fn, &buf);
if (ret) {
printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
sleep(1);
}
} while (ret && tries < 10);
if (ret) {
printf("failed to stat %s\n", fn);
}
}
static int get_bootloader_message_block(struct bootloader_message *out,
const Volume* v) {
wait_for_device(v->device);
FILE* f = fopen(v->device, "rb");
if (f == NULL) {
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
struct bootloader_message temp;
int count = fread(&temp, sizeof(temp), 1, f);
if (count != 1) {
LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
memcpy(out, &temp, sizeof(temp));
return 0;
}
static int set_bootloader_message_block(const struct bootloader_message *in,
const Volume* v) {
wait_for_device(v->device);
FILE* f = fopen(v->device, "wb");
if (f == NULL) {
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
int count = fwrite(in, sizeof(*in), 1, f);
if (count != 1) {
LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
return -1;
}
return 0;
}
/* Update Image
*
* - will be stored in the "cache" partition
@ -130,27 +211,27 @@ int set_bootloader_message(const struct bootloader_message *in) {
* - two raw bitmaps will be included, the "busy" and "fail" bitmaps
* - for dream, the bitmaps will be 320x480x16bpp RGB565
*/
#define UPDATE_MAGIC "MSM-RADIO-UPDATE"
#define UPDATE_MAGIC_SIZE 16
#define UPDATE_VERSION 0x00010000
struct update_header {
unsigned char MAGIC[UPDATE_MAGIC_SIZE];
unsigned version;
unsigned size;
unsigned image_offset;
unsigned image_length;
unsigned bitmap_width;
unsigned bitmap_height;
unsigned bitmap_bpp;
unsigned busy_bitmap_offset;
unsigned busy_bitmap_length;
unsigned fail_bitmap_offset;
unsigned fail_bitmap_length;
};
@ -159,113 +240,113 @@ int write_update_for_bootloader(
const char *update, int update_length,
int bitmap_width, int bitmap_height, int bitmap_bpp,
const char *busy_bitmap, const char *fail_bitmap) {
if (ensure_root_path_unmounted(CACHE_NAME)) {
LOGE("Can't unmount %s\n", CACHE_NAME);
if (ensure_path_unmounted("/cache")) {
LOGE("Can't unmount /cache\n");
return -1;
}
const MtdPartition *part = get_root_mtd_partition(CACHE_NAME);
const MtdPartition *part = mtd_find_partition_by_name("cache");
if (part == NULL) {
LOGE("Can't find %s\n", CACHE_NAME);
LOGE("Can't find cache\n");
return -1;
}
MtdWriteContext *write = mtd_write_partition(part);
if (write == NULL) {
LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't open cache\n(%s)\n", strerror(errno));
return -1;
}
/* Write an invalid (zero) header first, to disable any previous
* update and any other structured contents (like a filesystem),
* and as a placeholder for the amount of space required.
*/
struct update_header header;
memset(&header, 0, sizeof(header));
const ssize_t header_size = sizeof(header);
if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't write header to cache\n(%s)\n", strerror(errno));
mtd_write_close(write);
return -1;
}
/* Write each section individually block-aligned, so we can write
* each block independently without complicated buffering.
*/
memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
header.version = UPDATE_VERSION;
header.size = header_size;
off_t image_start_pos = mtd_erase_blocks(write, 0);
header.image_length = update_length;
if ((int) header.image_offset == -1 ||
mtd_write_data(write, update, update_length) != update_length) {
LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't write update to cache\n(%s)\n", strerror(errno));
mtd_write_close(write);
return -1;
}
off_t busy_start_pos = mtd_erase_blocks(write, 0);
header.image_offset = mtd_find_write_start(write, image_start_pos);
header.bitmap_width = bitmap_width;
header.bitmap_height = bitmap_height;
header.bitmap_bpp = bitmap_bpp;
int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;
header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
if ((int) header.busy_bitmap_offset == -1 ||
mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't write bitmap to cache\n(%s)\n", strerror(errno));
mtd_write_close(write);
return -1;
}
off_t fail_start_pos = mtd_erase_blocks(write, 0);
header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos);
header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
if ((int) header.fail_bitmap_offset == -1 ||
mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't write bitmap to cache\n(%s)\n", strerror(errno));
mtd_write_close(write);
return -1;
}
mtd_erase_blocks(write, 0);
header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos);
/* Write the header last, after all the blocks it refers to, so that
* when the magic number is installed everything is valid.
*/
if (mtd_write_close(write)) {
LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't finish writing cache\n(%s)\n", strerror(errno));
return -1;
}
write = mtd_write_partition(part);
if (write == NULL) {
LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't reopen cache\n(%s)\n", strerror(errno));
return -1;
}
if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't rewrite header to cache\n(%s)\n", strerror(errno));
mtd_write_close(write);
return -1;
}
if (mtd_erase_blocks(write, 0) != image_start_pos) {
LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Misalignment rewriting cache\n(%s)\n", strerror(errno));
mtd_write_close(write);
return -1;
}
if (mtd_write_close(write)) {
LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
LOGE("Can't finish header of cache\n(%s)\n", strerror(errno));
return -1;
}
return 0;
}

1293
commands.c

File diff suppressed because it is too large Load Diff

View File

@ -26,12 +26,15 @@ void ui_init();
int ui_wait_key(); // waits for a key/button press, returns the code
int ui_key_pressed(int key); // returns >0 if the code is currently pressed
int ui_text_visible(); // returns >0 if text log is currently visible
int ui_text_ever_visible(); // returns >0 if text log was ever visible
void ui_show_text(int visible);
void ui_clear_key_queue();
// Write a message to the on-screen log shown with Alt-L (also to stderr).
// The screen is small, and users may need to report these messages to support,
// so keep the output short and not too cryptic.
void ui_print(const char *fmt, ...);
void ui_print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void ui_printlogtail(int nb_lines);
void ui_reset_text_col();
void ui_set_show_text(int value);
@ -39,7 +42,7 @@ void ui_set_show_text(int value);
// Display some header text followed by a menu of items, which appears
// at the top of the screen (in place of any scrolling ui_print()
// output, if necessary).
int ui_start_menu(char** headers, char** items);
int ui_start_menu(char** headers, char** items, int initial_selection);
// Set the menu highlight to the given index, and return it (capped to
// the range [0..numitems).
int ui_menu_select(int sel);
@ -55,6 +58,7 @@ enum {
BACKGROUND_ICON_NONE,
BACKGROUND_ICON_INSTALLING,
BACKGROUND_ICON_ERROR,
BACKGROUND_ICON_CLOCKWORK,
BACKGROUND_ICON_FIRMWARE_INSTALLING,
BACKGROUND_ICON_FIRMWARE_ERROR,
NUM_BACKGROUND_ICONS
@ -85,12 +89,12 @@ void ui_show_indeterminate_progress();
void ui_reset_progress();
#define LOGE(...) ui_print("E:" __VA_ARGS__)
#define LOGW(...) fprintf(stderr, "W:" __VA_ARGS__)
#define LOGI(...) fprintf(stderr, "I:" __VA_ARGS__)
#define LOGW(...) fprintf(stdout, "W:" __VA_ARGS__)
#define LOGI(...) fprintf(stdout, "I:" __VA_ARGS__)
#if 0
#define LOGV(...) fprintf(stderr, "V:" __VA_ARGS__)
#define LOGD(...) fprintf(stderr, "D:" __VA_ARGS__)
#define LOGV(...) fprintf(stdout, "V:" __VA_ARGS__)
#define LOGD(...) fprintf(stdout, "D:" __VA_ARGS__)
#else
#define LOGV(...) do {} while (0)
#define LOGD(...) do {} while (0)
@ -99,4 +103,51 @@ void ui_reset_progress();
#define STRINGIFY(x) #x
#define EXPAND(x) STRINGIFY(x)
typedef struct {
const char* mount_point; // eg. "/cache". must live in the root directory.
const char* fs_type; // "yaffs2" or "ext4" or "vfat"
const char* device; // MTD partition name if fs_type == "yaffs"
// block device if fs_type == "ext4" or "vfat"
const char* device2; // alternative device to try if fs_type
// == "ext4" or "vfat" and mounting
// 'device' fails
long long length; // (ext4 partition only) when
// formatting, size to use for the
// partition. 0 or negative number
// means to format all but the last
// (that much).
const char* fs_type2;
const char* fs_options;
const char* fs_options2;
} Volume;
typedef struct {
// number of frames in indeterminate progress bar animation
int indeterminate_frames;
// number of frames per second to try to maintain when animating
int update_fps;
// number of frames in installing animation. may be zero for a
// static installation icon.
int installing_frames;
// the install icon is animated by drawing images containing the
// changing part over the base icon. These specify the
// coordinates of the upper-left corner.
int install_overlay_offset_x;
int install_overlay_offset_y;
} UIParameters;
// fopen a file, mounting volumes and making parent dirs as necessary.
FILE* fopen_path(const char *path, const char *mode);
#endif // RECOVERY_COMMON_H

68
default_recovery_keys.c Normal file
View File

@ -0,0 +1,68 @@
#include <linux/input.h>
#include "recovery_ui.h"
#include "common.h"
#include "extendedcommands.h"
int device_toggle_display(volatile char* key_pressed, int key_code) {
int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
if (alt && key_code == KEY_L)
return 1;
// allow toggling of the display if the correct key is pressed, and the display toggle is allowed or the display is currently off
if (ui_get_showing_back_button()) {
return 0;
//return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
}
return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_POWER || key_code == KEY_END);
}
int device_handle_key(int key_code, int visible) {
if (visible) {
switch (key_code) {
case KEY_CAPSLOCK:
case KEY_DOWN:
case KEY_VOLUMEDOWN:
case KEY_MENU:
return HIGHLIGHT_DOWN;
case KEY_LEFTSHIFT:
case KEY_UP:
case KEY_VOLUMEUP:
case KEY_HOME:
return HIGHLIGHT_UP;
case KEY_POWER:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display() && ui_menu_level > 0) {
return GO_BACK;
}
break;
case KEY_LEFTBRACE:
case KEY_ENTER:
case BTN_MOUSE:
case KEY_CAMERA:
case KEY_F21:
case KEY_SEND:
return SELECT_ITEM;
case KEY_END:
case KEY_BACKSPACE:
case KEY_SEARCH:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display() && ui_menu_level > 0) {
return GO_BACK;
}
case KEY_BACK:
if (ui_menu_level > 0) {
return GO_BACK;
}
}
}
return NO_ACTION;
}

View File

@ -23,70 +23,25 @@
char* MENU_HEADERS[] = { NULL };
char* MENU_ITEMS[] = { "reboot system now",
"apply sdcard:update.zip",
"install zip from sdcard",
"wipe data/factory reset",
"wipe cache partition",
"install zip from sdcard",
"backup and restore",
"mounts and storage",
"advanced",
NULL };
int device_toggle_display(volatile char* key_pressed, int key_code) {
int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
if (alt && key_code == KEY_L)
return 1;
// allow toggling of the display if the correct key is pressed, and the display toggle is allowed or the display is currently off
if (ui_get_showing_back_button()) {
return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
}
return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_POWER || key_code == KEY_END);
void device_ui_init(UIParameters* ui_parameters) {
}
int device_recovery_start() {
return 0;
}
int device_reboot_now(volatile char* key_pressed, int key_code) {
return 0;
}
int device_handle_key(int key_code, int visible) {
if (visible) {
switch (key_code) {
case KEY_CAPSLOCK:
case KEY_DOWN:
case KEY_VOLUMEDOWN:
return HIGHLIGHT_DOWN;
case KEY_LEFTSHIFT:
case KEY_UP:
case KEY_VOLUMEUP:
return HIGHLIGHT_UP;
case KEY_POWER:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display())
return GO_BACK;
break;
case KEY_LEFTBRACE:
case KEY_ENTER:
case BTN_MOUSE:
case KEY_CENTER:
case KEY_CAMERA:
case KEY_F21:
case KEY_SEND:
return SELECT_ITEM;
case KEY_END:
case KEY_BACKSPACE:
case KEY_BACK:
if (!get_allow_toggle_display())
return GO_BACK;
}
}
return NO_ACTION;
}
int device_perform_action(int which) {
return which;
}

View File

@ -33,12 +33,40 @@ int BooleanString(const char* s) {
}
char* Evaluate(State* state, Expr* expr) {
Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
if (v == NULL) return NULL;
if (v->type != VAL_STRING) {
ErrorAbort(state, "expecting string, got value type %d", v->type);
FreeValue(v);
return NULL;
}
char* result = v->data;
free(v);
return result;
}
Value* EvaluateValue(State* state, Expr* expr) {
return expr->fn(expr->name, state, expr->argc, expr->argv);
}
char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* StringValue(char* str) {
if (str == NULL) return NULL;
Value* v = malloc(sizeof(Value));
v->type = VAL_STRING;
v->size = strlen(str);
v->data = str;
return v;
}
void FreeValue(Value* v) {
if (v == NULL) return;
free(v->data);
free(v);
}
Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc == 0) {
return strdup("");
return StringValue(strdup(""));
}
char** strings = malloc(argc * sizeof(char*));
int i;
@ -67,10 +95,11 @@ char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
for (i = 0; i < argc; ++i) {
free(strings[i]);
}
return result;
free(strings);
return StringValue(result);
}
char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2 && argc != 3) {
free(state->errmsg);
state->errmsg = strdup("ifelse expects 2 or 3 arguments");
@ -83,18 +112,18 @@ char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (BooleanString(cond) == true) {
free(cond);
return Evaluate(state, argv[1]);
return EvaluateValue(state, argv[1]);
} else {
if (argc == 3) {
free(cond);
return Evaluate(state, argv[2]);
return EvaluateValue(state, argv[2]);
} else {
return cond;
return StringValue(cond);
}
}
}
char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
char* msg = NULL;
if (argc > 0) {
msg = Evaluate(state, argv[0]);
@ -108,7 +137,7 @@ char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
return NULL;
}
char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
@ -130,20 +159,20 @@ char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
return NULL;
}
}
return strdup("");
return StringValue(strdup(""));
}
char* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) {
return NULL;
}
int v = strtol(val, NULL, 10);
sleep(v);
return val;
return StringValue(val);
}
char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
@ -153,48 +182,44 @@ char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
fputs(v, stdout);
free(v);
}
return strdup("");
return StringValue(strdup(""));
}
char* LogicalAndFn(const char* name, State* state,
Value* LogicalAndFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == true) {
free(left);
return Evaluate(state, argv[1]);
return EvaluateValue(state, argv[1]);
} else {
return left;
return StringValue(left);
}
}
char* LogicalOrFn(const char* name, State* state,
int argc, Expr* argv[]) {
Value* LogicalOrFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == false) {
free(left);
return Evaluate(state, argv[1]);
return EvaluateValue(state, argv[1]);
} else {
return left;
return StringValue(left);
}
}
char* LogicalNotFn(const char* name, State* state,
int argc, Expr* argv[]) {
Value* LogicalNotFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) return NULL;
bool bv = BooleanString(val);
free(val);
if (bv) {
return strdup("");
} else {
return strdup("t");
}
return StringValue(strdup(bv ? "" : "t"));
}
char* SubstringFn(const char* name, State* state,
int argc, Expr* argv[]) {
Value* SubstringFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* needle = Evaluate(state, argv[0]);
if (needle == NULL) return NULL;
char* haystack = Evaluate(state, argv[1]);
@ -206,10 +231,10 @@ char* SubstringFn(const char* name, State* state,
char* result = strdup(strstr(haystack, needle) ? "t" : "");
free(needle);
free(haystack);
return result;
return StringValue(result);
}
char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
@ -221,10 +246,10 @@ char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
free(left);
free(right);
return result;
return StringValue(result);
}
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
@ -236,17 +261,17 @@ char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
free(left);
free(right);
return result;
return StringValue(result);
}
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* left = EvaluateValue(state, argv[0]);
if (left == NULL) return NULL;
free(left);
return Evaluate(state, argv[1]);
FreeValue(left);
return EvaluateValue(state, argv[1]);
}
char* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("less_than_int expects 2 arguments");
@ -277,10 +302,11 @@ char* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
done:
free(left);
free(right);
return strdup(result ? "t" : "");
return StringValue(strdup(result ? "t" : ""));
}
char* GreaterThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* GreaterThanIntFn(const char* name, State* state,
int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("greater_than_int expects 2 arguments");
@ -294,8 +320,8 @@ char* GreaterThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
return LessThanIntFn(name, state, 2, temp);
}
char* Literal(const char* name, State* state, int argc, Expr* argv[]) {
return strdup(name);
Value* Literal(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup(name));
}
Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
@ -389,11 +415,39 @@ int ReadArgs(State* state, Expr* argv[], int count, ...) {
for (j = 0; j < i; ++j) {
free(args[j]);
}
free(args);
return -1;
}
*(va_arg(v, char**)) = args[i];
}
va_end(v);
free(args);
return 0;
}
// Evaluate the expressions in argv, giving 'count' Value* (the ... is
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...) {
Value** args = malloc(count * sizeof(Value*));
va_list v;
va_start(v, count);
int i;
for (i = 0; i < count; ++i) {
args[i] = EvaluateValue(state, argv[i]);
if (args[i] == NULL) {
va_end(v);
int j;
for (j = 0; j < i; ++j) {
FreeValue(args[j]);
}
free(args);
return -1;
}
*(va_arg(v, Value**)) = args[i];
}
va_end(v);
free(args);
return 0;
}
@ -418,9 +472,30 @@ char** ReadVarArgs(State* state, int argc, Expr* argv[]) {
return args;
}
// Evaluate the expressions in argv, returning an array of Value*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// Values it contains.
Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) {
Value** args = (Value**)malloc(argc * sizeof(Value*));
int i = 0;
for (i = 0; i < argc; ++i) {
args[i] = EvaluateValue(state, argv[i]);
if (args[i] == NULL) {
int j;
for (j = 0; j < i; ++j) {
FreeValue(args[j]);
}
free(args);
return NULL;
}
}
return args;
}
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
char* ErrorAbort(State* state, char* format, ...) {
Value* ErrorAbort(State* state, char* format, ...) {
char* buffer = malloc(4096);
va_list v;
va_start(v, format);

View File

@ -17,6 +17,8 @@
#ifndef _EXPRESSION_H
#define _EXPRESSION_H
#include <unistd.h>
#include "yydefs.h"
#define MAX_STRING_LEN 1024
@ -39,8 +41,17 @@ typedef struct {
char* errmsg;
} State;
typedef char* (*Function)(const char* name, State* state,
int argc, Expr* argv[]);
#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
#define VAL_BLOB 2
typedef struct {
int type;
ssize_t size;
char* data;
} Value;
typedef Value* (*Function)(const char* name, State* state,
int argc, Expr* argv[]);
struct Expr {
Function fn;
@ -50,31 +61,41 @@ struct Expr {
int start, end;
};
// Take one of the Expr*s passed to the function as an argument,
// evaluate it, return the resulting Value. The caller takes
// ownership of the returned Value.
Value* EvaluateValue(State* state, Expr* expr);
// Take one of the Expr*s passed to the function as an argument,
// evaluate it, assert that it is a string, and return the resulting
// char*. The caller takes ownership of the returned char*. This is
// a convenience function for older functions that want to deal only
// with strings.
char* Evaluate(State* state, Expr* expr);
// Glue to make an Expr out of a literal.
char* Literal(const char* name, State* state, int argc, Expr* argv[]);
Value* Literal(const char* name, State* state, int argc, Expr* argv[]);
// Functions corresponding to various syntactic sugar operators.
// ("concat" is also available as a builtin function, to concatenate
// more than two strings.)
char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
char* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
Value* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
Value* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
// Convenience function for building expressions with a fixed number
// of arguments.
Expr* Build(Function fn, YYLTYPE loc, int count, ...);
// Global builtins, registered by RegisterBuiltins().
char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
char* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
char* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
// For setting and getting the global error string (when returning
@ -112,15 +133,31 @@ Function FindFunction(const char* name);
// to NULL, free the rest and return -1. Return 0 on success.
int ReadArgs(State* state, Expr* argv[], int count, ...);
// Evaluate the expressions in argv, giving 'count' Value* (the ... is
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...);
// Evaluate the expressions in argv, returning an array of char*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// strings it contains.
char** ReadVarArgs(State* state, int argc, Expr* argv[]);
// Evaluate the expressions in argv, returning an array of Value*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// Values it contains.
Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]);
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
char* ErrorAbort(State* state, char* format, ...);
Value* ErrorAbort(State* state, char* format, ...);
// Wrap a string into a Value, taking ownership of the string.
Value* StringValue(char* str);
// Free a Value object.
void FreeValue(Value* v);
#endif // _EXPRESSION_H

View File

@ -15,6 +15,8 @@
* limitations under the License.
*/
#include <string.h>
#include "expr.h"
#include "yydefs.h"
#include "parser.h"

View File

@ -42,11 +42,12 @@ int expect(const char* expr_str, const char* expected, int* errors) {
State state;
state.cookie = NULL;
state.script = expr_str;
state.script = strdup(expr_str);
state.errmsg = NULL;
result = Evaluate(&state, e);
free(state.errmsg);
free(state.script);
if (result == NULL && expected != NULL) {
fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
++*errors;
@ -181,6 +182,10 @@ int main(int argc, char** argv) {
}
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);

View File

@ -33,4 +33,6 @@ typedef struct {
} \
} while (0)
int yylex();
#endif

441
edifyscripting.c Normal file
View File

@ -0,0 +1,441 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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(""));
}
if (strcmp(path, "/data") == 0 && has_datadata()) {
ui_print("Formatting /datadata...\n", path);
if (0 != format_volume("/datadata")) {
free(path);
return StringValue(strdup(""));
}
if (0 != format_volume("/sdcard/.android_secure")) {
free(path);
return StringValue(strdup(""));
}
}
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);
if (0 != nandroid_restore(path, restoreboot, restoresystem, restoredata, restorecache, restoresdext, 0)) {
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));
}
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));
}
void RegisterRecoveryHooks() {
RegisterFunction("mount", MountFn);
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;
}
#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;
}

View File

@ -1,3 +1,5 @@
on early-init
start ueventd
on init
export PATH /sbin
@ -7,7 +9,11 @@ on init
symlink /system/etc /etc
mkdir /boot
mkdir /sdcard
mkdir /sd-ext
mkdir /datadata
mkdir /emmc
mkdir /system
mkdir /data
mkdir /cache
@ -21,13 +27,30 @@ on boot
class_start default
service ueventd /sbin/ueventd
critical
service recovery /sbin/recovery
service adbd /sbin/adbd recovery
disabled
on property:persist.service.adb.enable=1
start adbd
# Always start adbd on userdebug and eng builds
# In recovery, always run adbd as root.
on property:ro.debuggable=1
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18D1
write /sys/class/android_usb/android0/idProduct D001
write /sys/class/android_usb/android0/functions adb
#write /sys/class/android_usb/android0/enable 1
write /sys/class/android_usb/android0/iManufacturer $ro.product.manufacturer
write /sys/class/android_usb/android0/iProduct $ro.product.model
write /sys/class/android_usb/android0/iSerial $ro.serialno
#start adbd
setprop service.adb.root 1
on property:persist.service.adb.enable=0
stop adbd
# Restart adbd so it can run as root
on property:service.adb.root=1
write /sys/class/android_usb/android0/enable 0
restart adbd
write /sys/class/android_usb/android0/enable 1

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More