diff options
author | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-15 21:04:28 +0100 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2021-12-24 18:05:53 +0100 |
commit | c876d3bbefe0dc00c27ca0c12d29da5874946962 (patch) | |
tree | 69f468a185a369b01998314bc3ecc19b70f4fcaa /utils/mknwzboot | |
parent | 6c6f0757d7a902feb293be165d1490c42bc8e7ad (diff) | |
download | rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.tar.gz rockbox-c876d3bbefe0dc00c27ca0c12d29da5874946962.zip |
rbutil: Merge rbutil with utils folder.
rbutil uses several components from the utils folder, and can be
considered part of utils too. Having it in a separate folder is an
arbitrary split that doesn't help anymore these days, so merge them.
This also allows other utils to easily use libtools.make without the
need to navigate to a different folder.
Change-Id: I3fc2f4de19e3e776553efb5dea5f779dfec0dc21
Diffstat (limited to 'utils/mknwzboot')
-rw-r--r-- | utils/mknwzboot/Makefile | 52 | ||||
-rw-r--r-- | utils/mknwzboot/install_script.sh | 157 | ||||
-rw-r--r-- | utils/mknwzboot/main.c | 126 | ||||
-rw-r--r-- | utils/mknwzboot/mknwzboot.c | 294 | ||||
-rw-r--r-- | utils/mknwzboot/mknwzboot.h | 42 | ||||
-rw-r--r-- | utils/mknwzboot/uninstall_script.sh | 122 |
6 files changed, 793 insertions, 0 deletions
diff --git a/utils/mknwzboot/Makefile b/utils/mknwzboot/Makefile new file mode 100644 index 0000000000..3cbb2ef9dd --- /dev/null +++ b/utils/mknwzboot/Makefile | |||
@@ -0,0 +1,52 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | |||
8 | # We use the SB code available in the Rockbox utils/sbtools directory | ||
9 | UPGTOOLS_DIR=../../utils/nwztools/upgtools/ | ||
10 | CFLAGS += -I$(UPGTOOLS_DIR) -Wall | ||
11 | # std=gnu99 is required by MinGW on Windows (c99 is sufficient for Linux / MXE) | ||
12 | CFLAGS += -std=gnu99 -g -O3 | ||
13 | # dependencies | ||
14 | # FIXME make it work for windows and maybe embed crypto++ | ||
15 | |||
16 | # Location to pkg-config binary. | ||
17 | PKGCONFIG := pkg-config | ||
18 | |||
19 | # Distros could use different names for the crypto library. We try a list | ||
20 | # of candidate names, only one of them should be the valid one. | ||
21 | LIBCRYPTO_NAMES = libcryptopp libcrypto++ cryptopp crypto++ | ||
22 | |||
23 | $(foreach l,$(LIBCRYPTO_NAMES),\ | ||
24 | $(eval LDOPTS += $(shell $(PKGCONFIG) --silence-errors --libs $(l)))) | ||
25 | $(foreach l,$(LIBCRYPTO_NAMES),\ | ||
26 | $(eval CFLAGS += $(shell $(PKGCONFIG) --silence-errors --cflags $(l)))) | ||
27 | $(foreach l,$(LIBCRYPTO_NAMES),\ | ||
28 | $(eval CXXFLAGS += $(shell $(PKGCONFIG) --silence-errors --cflags $(l)))) | ||
29 | LDOPTS += -lpthread | ||
30 | |||
31 | OUTPUT = mknwzboot | ||
32 | |||
33 | # inputs for lib | ||
34 | UPGTOOLS_SOURCES = misc.c upg.c fwp.c mg.cpp md5.cpp | ||
35 | LIBSOURCES := mknwzboot.c install_script.c uninstall_script.c \ | ||
36 | $(addprefix $(UPGTOOLS_DIR),$(UPGTOOLS_SOURCES)) | ||
37 | # inputs for binary only | ||
38 | SOURCES := $(LIBSOURCES) main.c | ||
39 | # dependencies for binary | ||
40 | EXTRADEPS := | ||
41 | |||
42 | include ../libtools.make | ||
43 | |||
44 | install_script.c install_script.h: install_script.sh $(BIN2C) | ||
45 | $(BIN2C) install_script.sh install_script | ||
46 | |||
47 | uninstall_script.c uninstall_script.h: uninstall_script.sh $(BIN2C) | ||
48 | $(BIN2C) uninstall_script.sh uninstall_script | ||
49 | |||
50 | # explicit dependencies on install_script.{c,h} and mknwzboot.h | ||
51 | $(OBJDIR)mknwzboot.o: install_script.h install_script.c uninstall_script.h uninstall_script.c mknwzboot.h | ||
52 | $(OBJDIR)main.o: main.c mknwzboot.h | ||
diff --git a/utils/mknwzboot/install_script.sh b/utils/mknwzboot/install_script.sh new file mode 100644 index 0000000000..76bd12c4d5 --- /dev/null +++ b/utils/mknwzboot/install_script.sh | |||
@@ -0,0 +1,157 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # NOTE: busybox is using ash, a very posix and very pedantic shell, make sure | ||
4 | # you test your scripts with | ||
5 | # busybox sh -n <script> | ||
6 | # and if you really, really don't want to download busybox to try it, then go | ||
7 | # ahead and brick your device | ||
8 | |||
9 | # The updater script on the NWZ has a major bug/feature: | ||
10 | # it does NOT clear the update flag if the update scrit fails | ||
11 | # thus causing a update/reboot loop and a bricked device | ||
12 | # always clear to make sure we don't end up being screwed | ||
13 | nvpflag fup 0xFFFFFFFF | ||
14 | |||
15 | # go to /tmp | ||
16 | cd /tmp | ||
17 | |||
18 | # get content partition path | ||
19 | CONTENTS="/contents" | ||
20 | CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'` | ||
21 | |||
22 | # print a message to the screen and also on the standard output | ||
23 | # lcdprint x,y msg | ||
24 | lcdprint () | ||
25 | { | ||
26 | echo $2 | ||
27 | lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2" | ||
28 | } | ||
29 | |||
30 | # clear screen | ||
31 | lcdmsg -c "" | ||
32 | lcdprint 0,3 "Contents partition:\n$CONTENTS_PART" | ||
33 | |||
34 | # We need to remount the contents partition in read-write mode be able to | ||
35 | # write something on it | ||
36 | lcdprint 0,6 "Remount $CONTENTS rw" | ||
37 | mount -o remount,rw $CONTENTS_PART $CONTENTS | ||
38 | if [ "$?" != 0 ]; then | ||
39 | lcdprint 0,15 "ERROR: remount failed" | ||
40 | sleep 3 | ||
41 | exit 0 | ||
42 | fi | ||
43 | |||
44 | # redirect all output to a log file | ||
45 | exec > "$CONTENTS/install_dualboot_log.txt" 2>&1 | ||
46 | |||
47 | # import constants | ||
48 | . /install_script/constant.txt | ||
49 | _UPDATE_FN_=`nvpstr ufn` | ||
50 | ROOTFS_TMP_DIR=/tmp/rootfs | ||
51 | SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp | ||
52 | |||
53 | # mount root partition | ||
54 | lcdprint 0,7 "Mount root filesystem" | ||
55 | mkdir $ROOTFS_TMP_DIR | ||
56 | if [ "$?" != 0 ]; then | ||
57 | lcdprint 0,15 "ERROR: mkdir failed" | ||
58 | sleep 3 | ||
59 | exit 0 | ||
60 | fi | ||
61 | |||
62 | # If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and | ||
63 | # then ext2. | ||
64 | # NOTE some platforms probably use an mtd and this might need some fixing | ||
65 | if [ -e /usr/local/bin/icx_mount.ext4 ]; then | ||
66 | /usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR | ||
67 | else | ||
68 | false | ||
69 | fi | ||
70 | if [ "$?" != 0 ]; then | ||
71 | mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR | ||
72 | fi | ||
73 | if [ "$?" != 0 ]; then | ||
74 | mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR | ||
75 | fi | ||
76 | if [ "$?" != 0 ]; then | ||
77 | lcdprint 0,15 "ERROR: mount failed" | ||
78 | sleep 3 | ||
79 | exit 0 | ||
80 | fi | ||
81 | |||
82 | # rename the previous main application unless there is already a copy | ||
83 | lcdprint 0,8 "Backup OF" | ||
84 | if [ ! -e $SPIDERAPP_PATH.of ]; then | ||
85 | mv $SPIDERAPP_PATH $SPIDERAPP_PATH.of | ||
86 | fi | ||
87 | |||
88 | # extract our payload: the second file in the upgrade is a tar file | ||
89 | # the files in the archive have paths of the form ./absolute/path and we extract | ||
90 | # it at the rootfs mount it, so it can create/overwrite any file | ||
91 | # | ||
92 | # we need a small trick here: we want to pipe directly the output of the decryption | ||
93 | # tool to tar, to avoid using space in /tmp/ or on the user partition | ||
94 | lcdprint 0,9 "Install rockbox" | ||
95 | FIFO_FILE=/tmp/rb.fifo | ||
96 | mkfifo $FIFO_FILE | ||
97 | if [ "$?" != 0 ]; then | ||
98 | umount "$ROOTFS_TMP_DIR" | ||
99 | lcdprint 0,15 "ERROR: cannot create fifo" | ||
100 | sleep 3 | ||
101 | exit 0 | ||
102 | fi | ||
103 | fwpchk -f /contents/$_UPDATE_FN_.UPG -c -1 $FIFO_FILE & | ||
104 | #tar -tvf $FIFO_FILE | ||
105 | tar -C $ROOTFS_TMP_DIR -xvf $FIFO_FILE | ||
106 | if [ "$?" != 0 ]; then | ||
107 | umount "$ROOTFS_TMP_DIR" | ||
108 | lcdprint 0,15 "ERROR: extraction failed" | ||
109 | sleep 3 | ||
110 | exit 0 | ||
111 | fi | ||
112 | # wait for fwpchk | ||
113 | wait | ||
114 | if [ "$?" != 0 ]; then | ||
115 | umount "$ROOTFS_TMP_DIR" | ||
116 | lcdprint 0,15 "ERROR: no file to extract" | ||
117 | sleep 3 | ||
118 | exit 0 | ||
119 | fi | ||
120 | |||
121 | # create a symlink from /.rockbox to /contents/.rockbox (see dualboot code | ||
122 | # for why) | ||
123 | lcdprint 0,10 "Create rockbox symlink" | ||
124 | rm -f "$ROOTFS_TMP_DIR/.rockbox" | ||
125 | ln -s "$CONTENTS/.rockbox" "$ROOTFS_TMP_DIR/.rockbox" | ||
126 | if [ "$?" != 0 ]; then | ||
127 | umount "$ROOTFS_TMP_DIR" | ||
128 | lcdprint 0,15 "ERROR: cannot create rockbox symlink" | ||
129 | sleep 3 | ||
130 | exit 0 | ||
131 | fi | ||
132 | |||
133 | # unmount root partition | ||
134 | lcdprint 0,11 "Unmount root filesystem" | ||
135 | sync | ||
136 | if [ "$?" != 0 ]; then | ||
137 | umount "$ROOTFS_TMP_DIR" | ||
138 | lcdprint 0,15 "ERROR: sync failed" | ||
139 | sleep 3 | ||
140 | exit 0 | ||
141 | fi | ||
142 | |||
143 | umount $ROOTFS_TMP_DIR | ||
144 | if [ "$?" != 0 ]; then | ||
145 | lcdprint 0,15 "ERROR: umount failed" | ||
146 | sleep 3 | ||
147 | exit 0 | ||
148 | fi | ||
149 | |||
150 | # Success screen | ||
151 | lcdprint 0,15 "Rebooting in 3 seconds." | ||
152 | sleep 3 | ||
153 | sync | ||
154 | |||
155 | echo "Installation successful" | ||
156 | # finish | ||
157 | exit 0 | ||
diff --git a/utils/mknwzboot/main.c b/utils/mknwzboot/main.c new file mode 100644 index 0000000000..491a18043b --- /dev/null +++ b/utils/mknwzboot/main.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <getopt.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stdio.h> | ||
25 | #include <string.h> | ||
26 | #include "mknwzboot.h" | ||
27 | |||
28 | static void usage(void) | ||
29 | { | ||
30 | printf("Usage: mknwzboot [options | file]...\n"); | ||
31 | printf("Options:\n"); | ||
32 | printf(" -h/--help Display this message\n"); | ||
33 | printf(" -o <file> Set output file\n"); | ||
34 | printf(" -b <file> Set boot file\n"); | ||
35 | printf(" -d/--debug Enable debug output\n"); | ||
36 | printf(" -x Dump device informations\n"); | ||
37 | printf(" -u Create uninstall update\n"); | ||
38 | printf(" -m <model> Specify model\n"); | ||
39 | exit(1); | ||
40 | } | ||
41 | |||
42 | int main(int argc, char *argv[]) | ||
43 | { | ||
44 | char *outfile = NULL; | ||
45 | char *bootfile = NULL; | ||
46 | bool debug = false; | ||
47 | bool install = true; | ||
48 | const char *model = NULL; | ||
49 | |||
50 | if(argc == 1) | ||
51 | usage(); | ||
52 | |||
53 | while(1) | ||
54 | { | ||
55 | static struct option long_options[] = | ||
56 | { | ||
57 | {"help", no_argument, 0, 'h'}, | ||
58 | {"out-file", required_argument, 0, 'o'}, | ||
59 | {"boot-file", required_argument, 0, 'b'}, | ||
60 | {"debug", no_argument, 0, 'd'}, | ||
61 | {"dev-info", no_argument, 0, 'x'}, | ||
62 | {"uninstall", no_argument, 0, 'u'}, | ||
63 | {"model", required_argument, 0, 'm'}, | ||
64 | {0, 0, 0, 0} | ||
65 | }; | ||
66 | |||
67 | int c = getopt_long(argc, argv, "ho:b:dxum:", long_options, NULL); | ||
68 | if(c == -1) | ||
69 | break; | ||
70 | switch(c) | ||
71 | { | ||
72 | case 'd': | ||
73 | debug = true; | ||
74 | break; | ||
75 | case 'h': | ||
76 | usage(); | ||
77 | break; | ||
78 | case 'o': | ||
79 | outfile = optarg; | ||
80 | break; | ||
81 | case 'b': | ||
82 | bootfile = optarg; | ||
83 | break; | ||
84 | case 'x': | ||
85 | dump_nwz_dev_info(""); | ||
86 | return 0; | ||
87 | case 'u': | ||
88 | install = false; | ||
89 | break; | ||
90 | case 'm': | ||
91 | model = optarg; | ||
92 | break; | ||
93 | default: | ||
94 | abort(); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | if(!outfile) | ||
99 | { | ||
100 | printf("You must specify an output file\n"); | ||
101 | return 1; | ||
102 | } | ||
103 | if(install && !bootfile) | ||
104 | { | ||
105 | printf("You must specify a boot file for installation\n"); | ||
106 | return 1; | ||
107 | } | ||
108 | if(!install && !model) | ||
109 | { | ||
110 | printf("You must provide a model for uninstallation\n"); | ||
111 | return 1; | ||
112 | } | ||
113 | if(optind != argc) | ||
114 | { | ||
115 | printf("Extra arguments on command line\n"); | ||
116 | return 1; | ||
117 | } | ||
118 | |||
119 | int err; | ||
120 | if(install) | ||
121 | err = mknwzboot(bootfile, outfile, debug); | ||
122 | else | ||
123 | err = mknwzboot_uninst(model, outfile, debug); | ||
124 | printf("Result: %d\n", err); | ||
125 | return err; | ||
126 | } | ||
diff --git a/utils/mknwzboot/mknwzboot.c b/utils/mknwzboot/mknwzboot.c new file mode 100644 index 0000000000..22885674d8 --- /dev/null +++ b/utils/mknwzboot/mknwzboot.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <stdarg.h> | ||
24 | #include <string.h> | ||
25 | #include <ctype.h> | ||
26 | #include "mknwzboot.h" | ||
27 | #include "upg.h" | ||
28 | |||
29 | #include "install_script.h" | ||
30 | #include "uninstall_script.h" | ||
31 | |||
32 | struct nwz_model_desc_t | ||
33 | { | ||
34 | /* Descriptive name of this model */ | ||
35 | const char *model_name; | ||
36 | /* Model name used in the Rockbox header in ".sansa" files - these match the | ||
37 | -add parameter to the "scramble" tool */ | ||
38 | const char *rb_model_name; | ||
39 | /* Model number used to initialise the checksum in the Rockbox header in | ||
40 | ".sansa" files - these are the same as MODEL_NUMBER in config-target.h */ | ||
41 | const int rb_model_num; | ||
42 | /* Codename used in upgtool */ | ||
43 | const char *codename; | ||
44 | }; | ||
45 | |||
46 | static const struct nwz_model_desc_t nwz_models[] = | ||
47 | { | ||
48 | { "Sony NWZ-E350 Series", "e350", 109, "nwz-e350" }, | ||
49 | { "Sony NWZ-E450 Series", "e450", 100, "nwz-e450" }, | ||
50 | { "Sony NWZ-E460 Series", "e460", 101, "nwz-e460" }, | ||
51 | { "Sony NWZ-E470 Series", "e470", 103, "nwz-e470" }, | ||
52 | { "Sony NWZ-E580 Series", "e580", 102, "nwz-e580" }, | ||
53 | { "Sony NWZ-A10 Series", "a10", 104, "nwz-a10" }, | ||
54 | { "Sony NW-A20 Series", "a20", 106, "nw-a20" }, | ||
55 | { "Sony NWZ-A860 Series", "a860", 107, "nwz-a860" }, | ||
56 | { "Sony NWZ-S750 Series", "s750", 108, "nwz-s750" }, | ||
57 | }; | ||
58 | |||
59 | #define NR_NWZ_MODELS (sizeof(nwz_models) / sizeof(nwz_models[0])) | ||
60 | |||
61 | void dump_nwz_dev_info(const char *prefix) | ||
62 | { | ||
63 | printf("%smknwzboot models:\n", prefix); | ||
64 | for(int i = 0; i < NR_NWZ_MODELS; i++) | ||
65 | { | ||
66 | printf("%s %s: rb_model=%s rb_num=%d codename=%s\n", prefix, | ||
67 | nwz_models[i].model_name, nwz_models[i].rb_model_name, | ||
68 | nwz_models[i].rb_model_num, nwz_models[i].codename); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /* read a file to a buffer */ | ||
73 | static void *read_file(const char *file, size_t *size) | ||
74 | { | ||
75 | FILE *f = fopen(file, "rb"); | ||
76 | if(f == NULL) | ||
77 | { | ||
78 | printf("[ERR] Cannot open file '%s' for reading: %m\n", file); | ||
79 | return NULL; | ||
80 | } | ||
81 | fseek(f, 0, SEEK_END); | ||
82 | *size = ftell(f); | ||
83 | fseek(f, 0, SEEK_SET); | ||
84 | void *buffer = malloc(*size); | ||
85 | if(fread(buffer, *size, 1, f) != 1) | ||
86 | { | ||
87 | free(buffer); | ||
88 | fclose(f); | ||
89 | printf("[ERR] Cannot read file '%s': %m\n", file); | ||
90 | return NULL; | ||
91 | } | ||
92 | fclose(f); | ||
93 | return buffer; | ||
94 | } | ||
95 | |||
96 | /* write a file from a buffer */ | ||
97 | static bool write_file(const char *file, void *buffer, size_t size) | ||
98 | { | ||
99 | FILE *f = fopen(file, "wb"); | ||
100 | if(f == NULL) | ||
101 | { | ||
102 | printf("[ERR] Cannot open file '%s' for writing: %m\n", file); | ||
103 | return false; | ||
104 | } | ||
105 | if(fwrite(buffer, size, 1, f) != 1) | ||
106 | { | ||
107 | fclose(f); | ||
108 | printf("[ERR] Cannot write file '%s': %m\n", file); | ||
109 | return false; | ||
110 | } | ||
111 | fclose(f); | ||
112 | return true; | ||
113 | } | ||
114 | |||
115 | static unsigned int be2int(unsigned char* buf) | ||
116 | { | ||
117 | return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); | ||
118 | } | ||
119 | |||
120 | static int find_model(uint8_t *boot, size_t boot_size) | ||
121 | { | ||
122 | if(boot_size < 8) | ||
123 | { | ||
124 | printf("[ERR] Boot file is too small to be valid\n"); | ||
125 | return -1; | ||
126 | } | ||
127 | /* find model by comparing magic scramble value */ | ||
128 | int model = 0; | ||
129 | for(; model < NR_NWZ_MODELS; model++) | ||
130 | if(memcmp(boot + 4, nwz_models[model].rb_model_name, 4) == 0) | ||
131 | break; | ||
132 | if(model == NR_NWZ_MODELS) | ||
133 | { | ||
134 | printf("[ERR] This player is not supported: %.4s\n", boot + 4); | ||
135 | return -1; | ||
136 | } | ||
137 | printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name); | ||
138 | /* verify checksum */ | ||
139 | uint32_t sum = nwz_models[model].rb_model_num; | ||
140 | for(int i = 8; i < boot_size; i++) | ||
141 | sum += boot[i]; | ||
142 | if(sum != be2int(boot)) | ||
143 | { | ||
144 | printf("[ERR] Checksum mismatch\n"); | ||
145 | return -1; | ||
146 | } | ||
147 | return model; | ||
148 | } | ||
149 | |||
150 | static int find_model2(const char *model_str) | ||
151 | { | ||
152 | /* since it can be confusing for the user, we accept both rbmodel and codename */ | ||
153 | /* find model by comparing magic scramble value */ | ||
154 | int model = 0; | ||
155 | for(; model < NR_NWZ_MODELS; model++) | ||
156 | if(strcmp(nwz_models[model].rb_model_name, model_str) == 0 || | ||
157 | strcmp(nwz_models[model].codename, model_str) == 0) | ||
158 | break; | ||
159 | if(model == NR_NWZ_MODELS) | ||
160 | { | ||
161 | printf("[ERR] Unknown model: %s\n", model_str); | ||
162 | return -1; | ||
163 | } | ||
164 | printf("[INFO] Bootloader file for %s\n", nwz_models[model].model_name); | ||
165 | return model; | ||
166 | } | ||
167 | |||
168 | static bool get_model_keysig(int model, char key[NWZ_KEY_SIZE], char sig[NWZ_SIG_SIZE]) | ||
169 | { | ||
170 | const char *codename = nwz_models[model].codename; | ||
171 | for(int i = 0; g_model_list[i].model; i++) | ||
172 | if(strcmp(g_model_list[i].model, codename) == 0) | ||
173 | { | ||
174 | if(decrypt_keysig(g_model_list[i].kas, key, sig) == 0) | ||
175 | return true; | ||
176 | printf("[ERR] Cannot decrypt kas '%s'\n", g_model_list[i].kas); | ||
177 | return false; | ||
178 | } | ||
179 | printf("[ERR] Codename '%s' matches to entry in upg database\n", codename); | ||
180 | return false; | ||
181 | } | ||
182 | |||
183 | void nwz_printf(void *u, bool err, color_t c, const char *f, ...) | ||
184 | { | ||
185 | (void)err; | ||
186 | (void)c; | ||
187 | bool *debug = u; | ||
188 | va_list args; | ||
189 | va_start(args, f); | ||
190 | if(err || *debug) | ||
191 | vprintf(f, args); | ||
192 | va_end(args); | ||
193 | } | ||
194 | |||
195 | static void *memdup(void *data, size_t size) | ||
196 | { | ||
197 | void *buf = malloc(size); | ||
198 | memcpy(buf, data, size); | ||
199 | return buf; | ||
200 | } | ||
201 | |||
202 | int mknwzboot(const char *bootfile, const char *outfile, bool debug) | ||
203 | { | ||
204 | size_t boot_size; | ||
205 | uint8_t *boot = read_file(bootfile, &boot_size); | ||
206 | if(boot == NULL) | ||
207 | { | ||
208 | printf("[ERR] Cannot open boot file\n"); | ||
209 | return 1; | ||
210 | } | ||
211 | /* check that it is a valid scrambled file */ | ||
212 | int model = find_model(boot, boot_size); | ||
213 | if(model < 0) | ||
214 | { | ||
215 | free(boot); | ||
216 | printf("[ERR] Invalid boot file\n"); | ||
217 | return 2; | ||
218 | } | ||
219 | /* find keys */ | ||
220 | char key[NWZ_KEY_SIZE]; | ||
221 | char sig[NWZ_SIG_SIZE]; | ||
222 | if(!get_model_keysig(model, key, sig)) | ||
223 | { | ||
224 | printf("[ERR][INTERNAL] Cannot get keys for model\n"); | ||
225 | return 3; | ||
226 | } | ||
227 | /* create the upg file */ | ||
228 | struct upg_file_t *upg = upg_new(); | ||
229 | /* first file is the install script: we have to copy data because upg_free() | ||
230 | * will free it */ | ||
231 | upg_append(upg, memdup(install_script, LEN_install_script), LEN_install_script); | ||
232 | /* second file is the bootloader content (expected to be a tar file): we have | ||
233 | * to copy data because upg_free() will free it */ | ||
234 | upg_append(upg, memdup(boot + 8, boot_size - 8), boot_size - 8); | ||
235 | free(boot); | ||
236 | /* write file to buffer */ | ||
237 | size_t upg_size; | ||
238 | void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf); | ||
239 | upg_free(upg); | ||
240 | if(upg_buf == NULL) | ||
241 | { | ||
242 | printf("[ERR] Cannot create UPG file\n"); | ||
243 | return 4; | ||
244 | } | ||
245 | if(!write_file(outfile, upg_buf, upg_size)) | ||
246 | { | ||
247 | free(upg_buf); | ||
248 | printf("[ERR] Cannpt write UPG file\n"); | ||
249 | return 5; | ||
250 | } | ||
251 | free(upg_buf); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | int mknwzboot_uninst(const char *model_string, const char *outfile, bool debug) | ||
256 | { | ||
257 | /* check that it is a valid scrambled file */ | ||
258 | int model = find_model2(model_string); | ||
259 | if(model < 0) | ||
260 | { | ||
261 | printf("[ERR] Invalid model\n"); | ||
262 | return 2; | ||
263 | } | ||
264 | /* find keys */ | ||
265 | char key[NWZ_KEY_SIZE]; | ||
266 | char sig[NWZ_SIG_SIZE]; | ||
267 | if(!get_model_keysig(model, key, sig)) | ||
268 | { | ||
269 | printf("[ERR][INTERNAL] Cannot get keys for model\n"); | ||
270 | return 3; | ||
271 | } | ||
272 | /* create the upg file */ | ||
273 | struct upg_file_t *upg = upg_new(); | ||
274 | /* first file is the uninstall script: we have to copy data because upg_free() | ||
275 | * will free it */ | ||
276 | upg_append(upg, memdup(uninstall_script, LEN_uninstall_script), LEN_uninstall_script); | ||
277 | /* write file to buffer */ | ||
278 | size_t upg_size; | ||
279 | void *upg_buf = upg_write_memory(upg, key, sig, &upg_size, &debug, nwz_printf); | ||
280 | upg_free(upg); | ||
281 | if(upg_buf == NULL) | ||
282 | { | ||
283 | printf("[ERR] Cannot create UPG file\n"); | ||
284 | return 4; | ||
285 | } | ||
286 | if(!write_file(outfile, upg_buf, upg_size)) | ||
287 | { | ||
288 | free(upg_buf); | ||
289 | printf("[ERR] Cannpt write UPG file\n"); | ||
290 | return 5; | ||
291 | } | ||
292 | free(upg_buf); | ||
293 | return 0; | ||
294 | } | ||
diff --git a/utils/mknwzboot/mknwzboot.h b/utils/mknwzboot/mknwzboot.h new file mode 100644 index 0000000000..31f2c6355e --- /dev/null +++ b/utils/mknwzboot/mknwzboot.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef MKIMXBOOT_H | ||
23 | #define MKIMXBOOT_H | ||
24 | |||
25 | #include <stdbool.h> | ||
26 | #include <stdint.h> | ||
27 | #include <sys/types.h> | ||
28 | |||
29 | #ifdef __cplusplus | ||
30 | extern "C" { | ||
31 | #endif | ||
32 | |||
33 | void dump_nwz_dev_info(const char *prefix); | ||
34 | /* return 0 on success */ | ||
35 | int mknwzboot(const char *bootfile, const char *outfile, bool debug); | ||
36 | int mknwzboot_uninst(const char *model, const char *outfile, bool debug); | ||
37 | |||
38 | #ifdef __cplusplus | ||
39 | } | ||
40 | #endif | ||
41 | #endif | ||
42 | |||
diff --git a/utils/mknwzboot/uninstall_script.sh b/utils/mknwzboot/uninstall_script.sh new file mode 100644 index 0000000000..0e409c63cd --- /dev/null +++ b/utils/mknwzboot/uninstall_script.sh | |||
@@ -0,0 +1,122 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # NOTE: busybox is using ash, a very posix and very pedantic shell, make sure | ||
4 | # you test your scripts with | ||
5 | # busybox sh -n <script> | ||
6 | # and if you really, really don't want to download busybox to try it, then go | ||
7 | # ahead and brick your device | ||
8 | |||
9 | # The updater script on the NWZ has a major bug/feature: | ||
10 | # it does NOT clear the update flag if the update scrit fails | ||
11 | # thus causing a update/reboot loop and a bricked device | ||
12 | # always clear to make sure we don't end up being screwed | ||
13 | nvpflag fup 0xFFFFFFFF | ||
14 | |||
15 | # go to /tmp | ||
16 | cd /tmp | ||
17 | |||
18 | # get content partition path | ||
19 | CONTENTS="/contents" | ||
20 | CONTENTS_PART=`mount | grep contents | awk '{ print $1 }'` | ||
21 | |||
22 | # print a message to the screen and also on the standard output | ||
23 | # lcdprint x,y msg | ||
24 | lcdprint () | ||
25 | { | ||
26 | echo $2 | ||
27 | lcdmsg -f /usr/local/bin/font_08x12.bmp -l $1 "$2" | ||
28 | } | ||
29 | |||
30 | # clear screen | ||
31 | lcdmsg -c "" | ||
32 | lcdprint 0,3 "Contents partition:\n$CONTENTS_PART" | ||
33 | |||
34 | # We need to remount the contents partition in read-write mode be able to | ||
35 | # write something on it | ||
36 | lcdprint 0,6 "Remount $CONTENTS rw" | ||
37 | mount -o remount,rw $CONTENTS_PART $CONTENTS | ||
38 | if [ "$?" != 0 ]; then | ||
39 | lcdprint 0,15 "ERROR: remount failed" | ||
40 | sleep 3 | ||
41 | exit 0 | ||
42 | fi | ||
43 | |||
44 | # redirect all output to a log file | ||
45 | exec > "$CONTENTS/uninstall_dualboot_log.txt" 2>&1 | ||
46 | |||
47 | # import constants | ||
48 | . /install_script/constant.txt | ||
49 | ROOTFS_TMP_DIR=/tmp/rootfs | ||
50 | SPIDERAPP_PATH=$ROOTFS_TMP_DIR/usr/local/bin/SpiderApp | ||
51 | |||
52 | # mount root partition | ||
53 | lcdprint 0,7 "Mount root filesystem" | ||
54 | mkdir $ROOTFS_TMP_DIR | ||
55 | if [ "$?" != 0 ]; then | ||
56 | lcdprint 0,15 "ERROR: mkdir failed" | ||
57 | sleep 3 | ||
58 | exit 0 | ||
59 | fi | ||
60 | |||
61 | # If there is an ext4 mounter, try it. Otherwise or on failure, try ext3 and | ||
62 | # then ext2. | ||
63 | # NOTE some platforms probably use an mtd and this might need some fixing | ||
64 | if [ -e /usr/local/bin/icx_mount.ext4 ]; then | ||
65 | /usr/local/bin/icx_mount.ext4 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR | ||
66 | else | ||
67 | false | ||
68 | fi | ||
69 | if [ "$?" != 0 ]; then | ||
70 | mount -t ext3 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR | ||
71 | fi | ||
72 | if [ "$?" != 0 ]; then | ||
73 | mount -t ext2 $COMMON_ROOTFS_PARTITION $ROOTFS_TMP_DIR | ||
74 | fi | ||
75 | if [ "$?" != 0 ]; then | ||
76 | lcdprint 0,15 "ERROR: mount failed" | ||
77 | sleep 3 | ||
78 | exit 0 | ||
79 | fi | ||
80 | |||
81 | # the installer renames the OF to $SPIDERAPP_PATH.of so if it does not exists | ||
82 | # print an error | ||
83 | lcdprint 0,8 "Restore OF" | ||
84 | if [ ! -e $SPIDERAPP_PATH.of ]; then | ||
85 | lcdprint 0,15 "ERROR: cannot find OF" | ||
86 | lcdprint 0,16 "ERROR: is Rockbox installed?" | ||
87 | sleep 3 | ||
88 | exit 0 | ||
89 | fi | ||
90 | # restore the OF | ||
91 | mv $SPIDERAPP_PATH.of $SPIDERAPP_PATH | ||
92 | if [ "$?" != 0 ]; then | ||
93 | lcdprint 0,15 "ERROR: restore failed" | ||
94 | sleep 3 | ||
95 | exit 0 | ||
96 | fi | ||
97 | |||
98 | # unmount root partition | ||
99 | lcdprint 0,11 "Unmount root filesystem" | ||
100 | sync | ||
101 | if [ "$?" != 0 ]; then | ||
102 | umount "$ROOTFS_TMP_DIR" | ||
103 | lcdprint 0,15 "ERROR: sync failed" | ||
104 | sleep 3 | ||
105 | exit 0 | ||
106 | fi | ||
107 | |||
108 | umount $ROOTFS_TMP_DIR | ||
109 | if [ "$?" != 0 ]; then | ||
110 | lcdprint 0,15 "ERROR: umount failed" | ||
111 | sleep 3 | ||
112 | exit 0 | ||
113 | fi | ||
114 | |||
115 | # Success screen | ||
116 | lcdprint 0,15 "Rebooting in 3 seconds." | ||
117 | sleep 3 | ||
118 | sync | ||
119 | |||
120 | echo "Uninstallation successful" | ||
121 | # finish | ||
122 | exit 0 | ||