1
0
Fork 0
forked from len0rd/rockbox

mknwzboot: add support for uninstallation

There is not need for a bootloader file to create an uninstall firmware so one
needs to provide a model.
Also cleanup the install script a bit by factoring message into a function, also
print them to the log so that the user can report what was printed on the screen
easily. The uninstall script is quite trivial, it remounts the rootfs and restores
the backed up OF to its right place.

Change-Id: I1f5c0efeb965fdc7fe17f45c2753c0f52c34f7f1
This commit is contained in:
Amaury Pouly 2017-09-17 22:16:50 +02:00
parent ac59669d46
commit 7de1d8b70f
6 changed files with 247 additions and 25 deletions

View file

@ -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

View file

@ -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

View file

@ -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\n");
printf("You must specify a boot file for installation\n");
return 1;
}
if(!install && !model)
{
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;
}

View file

@ -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;
}

View file

@ -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
}

View file

@ -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