diff options
-rw-r--r-- | rbutil/mknwzboot/Makefile | 9 | ||||
-rw-r--r-- | rbutil/mknwzboot/install_script.sh | 51 | ||||
-rw-r--r-- | rbutil/mknwzboot/main.c | 29 | ||||
-rw-r--r-- | rbutil/mknwzboot/mknwzboot.c | 60 | ||||
-rw-r--r-- | rbutil/mknwzboot/mknwzboot.h | 1 | ||||
-rw-r--r-- | rbutil/mknwzboot/uninstall_script.sh | 122 |
6 files changed, 247 insertions, 25 deletions
diff --git a/rbutil/mknwzboot/Makefile b/rbutil/mknwzboot/Makefile index 9530ac369e..fd80106b83 100644 --- a/rbutil/mknwzboot/Makefile +++ b/rbutil/mknwzboot/Makefile @@ -18,7 +18,7 @@ OUTPUT = mknwzboot # inputs for lib UPGTOOLS_SOURCES = misc.c upg.c fwp.c mg.cpp md5.cpp -LIBSOURCES := mknwzboot.c install_script.c \ +LIBSOURCES := mknwzboot.c install_script.c uninstall_script.c \ $(addprefix $(UPGTOOLS_DIR),$(UPGTOOLS_SOURCES)) # inputs for binary only SOURCES := $(LIBSOURCES) main.c @@ -30,6 +30,9 @@ include ../libtools.make install_script.c install_script.h: install_script.sh $(BIN2C) $(BIN2C) install_script.sh install_script +uninstall_script.c uninstall_script.h: uninstall_script.sh $(BIN2C) + $(BIN2C) uninstall_script.sh uninstall_script + # explicit dependencies on install_script.{c,h} and mknwzboot.h -$(OBJDIR)mknwzboot.o: install_script.h install_script.c mknwzboot.h -$(OBJDIR)main.o: install_script.h install_script.c main.c mknwzboot.h +$(OBJDIR)mknwzboot.o: install_script.h install_script.c uninstall_script.h uninstall_script.c mknwzboot.h +$(OBJDIR)main.o: main.c mknwzboot.h diff --git a/rbutil/mknwzboot/install_script.sh b/rbutil/mknwzboot/install_script.sh index 18296d257e..76bd12c4d5 100644 --- a/rbutil/mknwzboot/install_script.sh +++ b/rbutil/mknwzboot/install_script.sh @@ -1,5 +1,11 @@ #!/bin/sh +# NOTE: busybox is using ash, a very posix and very pedantic shell, make sure +# you test your scripts with +# busybox sh -n <script> +# and if you really, really don't want to download busybox to try it, then go +# ahead and brick your device + # The updater script on the NWZ has a major bug/feature: # it does NOT clear the update flag if the update scrit fails # thus causing a update/reboot loop and a bricked device @@ -13,14 +19,24 @@ cd /tmp CONTENTS="/contents" CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'` -lcdmsg -c -f /usr/local/bin/font_08x12.bmp -l 0,3 "Contents partition:\n$CONTENTS_PART" +# print a message to the screen and also on the standard output +# lcdprint x,y msg +lcdprint () +{ + echo $2 + lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2" +} + +# clear screen +lcdmsg -c "" +lcdprint 0,3 "Contents partition:\n$CONTENTS_PART" # We need to remount the contents partition in read-write mode be able to # write something on it -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,6 "Remount $CONTENTS rw" +lcdprint 0,6 "Remount $CONTENTS rw" mount -o remount,rw $CONTENTS_PART $CONTENTS if [ "$?" != 0 ]; then - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: remount failed" + lcdprint 0,15 "ERROR: remount failed" sleep 3 exit 0 fi @@ -35,10 +51,10 @@ ROOTFS_TMP_DIR=/tmp/rootfs SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp # mount root partition -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,7 "Mount root filesystem" +lcdprint 0,7 "Mount root filesystem" mkdir $ROOTFS_TMP_DIR if [ "$?" != 0 ]; then - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mkdir failed" + lcdprint 0,15 "ERROR: mkdir failed" sleep 3 exit 0 fi @@ -58,13 +74,13 @@ if [ "$?" != 0 ]; then mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR fi if [ "$?" != 0 ]; then - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: mount failed" + lcdprint 0,15 "ERROR: mount failed" sleep 3 exit 0 fi # rename the previous main application unless there is already a copy -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,8 "Backup OF" +lcdprint 0,8 "Backup OF" if [ ! -e $SPIDERAPP_PATH.of ]; then mv $SPIDERAPP_PATH $SPIDERAPP_PATH.of fi @@ -75,12 +91,12 @@ fi # # we need a small trick here: we want to pipe directly the output of the decryption # tool to tar, to avoid using space in /tmp/ or on the user partition -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,9 "Install rockbox" +lcdprint 0,9 "Install rockbox" FIFO_FILE=/tmp/rb.fifo mkfifo $FIFO_FILE if [ "$?" != 0 ]; then umount "$ROOTFS_TMP_DIR" - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot create fifo" + lcdprint 0,15 "ERROR: cannot create fifo" sleep 3 exit 0 fi @@ -89,7 +105,7 @@ fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $FIFO_FILE & tar -C $ROOTFS_TMP_DIR -xvf $FIFO_FILE if [ "$?" != 0 ]; then umount "$ROOTFS_TMP_DIR" - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: extraction failed" + lcdprint 0,15 "ERROR: extraction failed" sleep 3 exit 0 fi @@ -97,46 +113,45 @@ fi wait if [ "$?" != 0 ]; then umount "$ROOTFS_TMP_DIR" - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: no file to extract" + lcdprint 0,15 "ERROR: no file to extract" sleep 3 exit 0 fi # create a symlink from /.rockbox to /contents/.rockbox (see dualboot code # for why) -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,10 "Create rockbox symlink" +lcdprint 0,10 "Create rockbox symlink" rm -f "$ROOTFS_TMP_DIR/.rockbox" ln -s "$CONTENTS/.rockbox" "$ROOTFS_TMP_DIR/.rockbox" if [ "$?" != 0 ]; then umount "$ROOTFS_TMP_DIR" - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: cannot create rockbox symlink" + lcdprint 0,15 "ERROR: cannot create rockbox symlink" sleep 3 exit 0 fi # unmount root partition -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,11 "Unmount root filesystem" +lcdprint 0,11 "Unmount root filesystem" sync if [ "$?" != 0 ]; then umount "$ROOTFS_TMP_DIR" - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: sync failed" + lcdprint 0,15 "ERROR: sync failed" sleep 3 exit 0 fi umount $ROOTFS_TMP_DIR if [ "$?" != 0 ]; then - lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "ERROR: umount failed" + lcdprint 0,15 "ERROR: umount failed" sleep 3 exit 0 fi # Success screen -lcdmsg -f /usr/local/bin/font_08x12.bmp -l 0,15 "Rebooting in 3 seconds." +lcdprint 0,15 "Rebooting in 3 seconds." sleep 3 sync echo "Installation successful" # finish exit 0 - diff --git a/rbutil/mknwzboot/main.c b/rbutil/mknwzboot/main.c index a36c24eaf5..491a18043b 100644 --- a/rbutil/mknwzboot/main.c +++ b/rbutil/mknwzboot/main.c @@ -34,6 +34,8 @@ static void usage(void) printf(" -b <file> Set boot file\n"); printf(" -d/--debug Enable debug output\n"); printf(" -x Dump device informations\n"); + printf(" -u Create uninstall update\n"); + printf(" -m <model> Specify model\n"); exit(1); } @@ -42,6 +44,8 @@ int main(int argc, char *argv[]) char *outfile = NULL; char *bootfile = NULL; bool debug = false; + bool install = true; + const char *model = NULL; if(argc == 1) usage(); @@ -55,10 +59,12 @@ int main(int argc, char *argv[]) {"boot-file", required_argument, 0, 'b'}, {"debug", no_argument, 0, 'd'}, {"dev-info", no_argument, 0, 'x'}, + {"uninstall", no_argument, 0, 'u'}, + {"model", required_argument, 0, 'm'}, {0, 0, 0, 0} }; - int c = getopt_long(argc, argv, "ho:b:dx", long_options, NULL); + int c = getopt_long(argc, argv, "ho:b:dxum:", long_options, NULL); if(c == -1) break; switch(c) @@ -77,6 +83,12 @@ int main(int argc, char *argv[]) break; case 'x': dump_nwz_dev_info(""); + return 0; + case 'u': + install = false; + break; + case 'm': + model = optarg; break; default: abort(); @@ -88,9 +100,14 @@ int main(int argc, char *argv[]) printf("You must specify an output file\n"); return 1; } - if(!bootfile) + if(install && !bootfile) + { + printf("You must specify a boot file for installation\n"); + return 1; + } + if(!install && !model) { - printf("You must specify a boot file\n"); + printf("You must provide a model for uninstallation\n"); return 1; } if(optind != argc) @@ -99,7 +116,11 @@ int main(int argc, char *argv[]) return 1; } - int err = mknwzboot(bootfile, outfile, debug); + int err; + if(install) + err = mknwzboot(bootfile, outfile, debug); + else + err = mknwzboot_uninst(model, outfile, debug); printf("Result: %d\n", err); return err; } diff --git a/rbutil/mknwzboot/mknwzboot.c b/rbutil/mknwzboot/mknwzboot.c index b41692c9fd..2e574a94d7 100644 --- a/rbutil/mknwzboot/mknwzboot.c +++ b/rbutil/mknwzboot/mknwzboot.c @@ -27,6 +27,7 @@ #include "upg.h" #include "install_script.h" +#include "uninstall_script.h" struct nwz_model_desc_t { @@ -145,6 +146,24 @@ static int find_model(uint8_t *boot, size_t boot_size) return model; } +static int find_model2(const char *model_str) +{ + /* since it can be confusing for the user, we accept both rbmodel and codename */ + /* find model by comparing magic scramble value */ + int model = 0; + for(; model < NR_NWZ_MODELS; model++) + if(strcmp(nwz_models[model].rb_model_name, model_str) == 0 || + strcmp(nwz_models[model].codename, model_str) == 0) + break; + if(model == NR_NWZ_MODELS) + { + printf("[ERR] Unknown model: %s\n", model_str); + return -1; + } + printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name); + return model; +} + static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE]) { const char *codename = nwz_models[model].codename; @@ -231,3 +250,44 @@ int mknwzboot(const char *bootfile, const char *outfile, bool debug) free(upg_buf); return 0; } + +int mknwzboot_uninst(const char *model_string, const char *outfile, bool debug) +{ + /* check that it is a valid scrambled file */ + int model = find_model2(model_string); + if(model < 0) + { + printf("[ERR] Invalid model\n"); + return 2; + } + /* find keys */ + char key[NWZ_KEY_SIZE]; + char sig[NWZ_SIG_SIZE]; + if(!get_model_keysig(model, key, sig)) + { + printf("[ERR][INTERNAL] Cannot get keys for model\n"); + return 3; + } + /* create the upg file */ + struct upg_file_t *upg = upg_new(); + /* first file is the uninstall script: we have to copy data because upg_free() + * will free it */ + upg_append(upg, memdup(uninstall_script, LEN_uninstall_script), LEN_uninstall_script); + /* write file to buffer */ + size_t upg_size; + void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf); + upg_free(upg); + if(upg_buf == NULL) + { + printf("[ERR] Cannot create UPG file\n"); + return 4; + } + if(!write_file(outfile, upg_buf, upg_size)) + { + free(upg_buf); + printf("[ERR] Cannpt write UPG file\n"); + return 5; + } + free(upg_buf); + return 0; +} diff --git a/rbutil/mknwzboot/mknwzboot.h b/rbutil/mknwzboot/mknwzboot.h index f46dd75d5c..31f2c6355e 100644 --- a/rbutil/mknwzboot/mknwzboot.h +++ b/rbutil/mknwzboot/mknwzboot.h @@ -33,6 +33,7 @@ extern "C" { void dump_nwz_dev_info(const char *prefix); /* return 0 on success */ int mknwzboot(const char *bootfile, const char *outfile, bool debug); +int mknwzboot_uninst(const char *model, const char *outfile, bool debug); #ifdef __cplusplus } diff --git a/rbutil/mknwzboot/uninstall_script.sh b/rbutil/mknwzboot/uninstall_script.sh new file mode 100644 index 0000000000..0e409c63cd --- /dev/null +++ b/rbutil/mknwzboot/uninstall_script.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +# NOTE: busybox is using ash, a very posix and very pedantic shell, make sure +# you test your scripts with +# busybox sh -n <script> +# and if you really, really don't want to download busybox to try it, then go +# ahead and brick your device + +# The updater script on the NWZ has a major bug/feature: +# it does NOT clear the update flag if the update scrit fails +# thus causing a update/reboot loop and a bricked device +# always clear to make sure we don't end up being screwed +nvpflag fup 0xFFFFFFFF + +# go to /tmp +cd /tmp + +# get content partition path +CONTENTS="/contents" +CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'` + +# print a message to the screen and also on the standard output +# lcdprint x,y msg +lcdprint () +{ + echo $2 + lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2" +} + +# clear screen +lcdmsg -c "" +lcdprint 0,3 "Contents partition:\n$CONTENTS_PART" + +# We need to remount the contents partition in read-write mode be able to +# write something on it +lcdprint 0,6 "Remount $CONTENTS rw" +mount -o remount,rw $CONTENTS_PART $CONTENTS +if [ "$?" != 0 ]; then + lcdprint 0,15 "ERROR: remount failed" + sleep 3 + exit 0 +fi + +# redirect all output to a log file +exec > "$CONTENTS/uninstall_dualboot_log.txt" 2>&1 + +# import constants +. /install_script/constant.txt +ROOTFS_TMP_DIR=/tmp/rootfs +SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp + +# mount root partition +lcdprint 0,7 "Mount root filesystem" +mkdir $ROOTFS_TMP_DIR +if [ "$?" != 0 ]; then + lcdprint 0,15 "ERROR: mkdir failed" + sleep 3 + exit 0 +fi + +# If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and +# then ext2. +# NOTE some platforms probably use an mtd and this might need some fixing +if [ -e /usr/local/bin/icx_mount.ext4 ]; then + /usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR +else + false +fi +if [ "$?" != 0 ]; then + mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR +fi +if [ "$?" != 0 ]; then + mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR +fi +if [ "$?" != 0 ]; then + lcdprint 0,15 "ERROR: mount failed" + sleep 3 + exit 0 +fi + +# the installer renames the OF to $SPIDERAPP_PATH.of so if it does not exists +# print an error +lcdprint 0,8 "Restore OF" +if [ ! -e $SPIDERAPP_PATH.of ]; then + lcdprint 0,15 "ERROR: cannot find OF" + lcdprint 0,16 "ERROR: is Rockbox installed?" + sleep 3 + exit 0 +fi +# restore the OF +mv $SPIDERAPP_PATH.of $SPIDERAPP_PATH +if [ "$?" != 0 ]; then + lcdprint 0,15 "ERROR: restore failed" + sleep 3 + exit 0 +fi + +# unmount root partition +lcdprint 0,11 "Unmount root filesystem" +sync +if [ "$?" != 0 ]; then + umount "$ROOTFS_TMP_DIR" + lcdprint 0,15 "ERROR: sync failed" + sleep 3 + exit 0 +fi + +umount $ROOTFS_TMP_DIR +if [ "$?" != 0 ]; then + lcdprint 0,15 "ERROR: umount failed" + sleep 3 + exit 0 +fi + +# Success screen +lcdprint 0,15 "Rebooting in 3 seconds." +sleep 3 +sync + +echo "Uninstallation successful" +# finish +exit 0 |