summaryrefslogtreecommitdiff
path: root/rbutil/jztool/jztool.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-04-13 16:58:15 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-04-17 20:23:19 +0000
commitb41d53792c4c4e4abd6d810b2765d865775f5104 (patch)
treeae3e02b961c655cd49b3c13bc895a18547ceeec1 /rbutil/jztool/jztool.c
parent1b8542490da3283dfa0ce0f3363f16eab0609815 (diff)
downloadrockbox-b41d53792c4c4e4abd6d810b2765d865775f5104.tar.gz
rockbox-b41d53792c4c4e4abd6d810b2765d865775f5104.zip
jztool: New utility for installing a bootloader on FiiO M3K
At present, this is just a command line tool for Linux only. Integrating this with the Rockbox utility and porting to other platforms should be straightforward; the README contains more information. Change-Id: Ie66fc837a02ab13c878925360cabc9805597548a
Diffstat (limited to 'rbutil/jztool/jztool.c')
-rw-r--r--rbutil/jztool/jztool.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/rbutil/jztool/jztool.c b/rbutil/jztool/jztool.c
new file mode 100644
index 0000000000..5aae8d7457
--- /dev/null
+++ b/rbutil/jztool/jztool.c
@@ -0,0 +1,227 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
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 "jztool.h"
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdbool.h>
27
28jz_context* jz = NULL;
29const jz_device_info* dev_info = NULL;
30int dev_action = -1;
31jz_paramlist* action_params = NULL;
32
33void usage(void)
34{
35 printf("Usage:\n"
36 " jztool [global options] <device> <action> [action options]\n"
37 "\n"
38 "Global options:\n"
39 "\n"
40 " -h, --help Display this help\n"
41 " -q, --quiet Don't log anything except errors\n"
42 " -v, --verbose Display detailed logging output\n"
43 " -l, --loglevel LEVEL Set log level\n");
44
45 printf("Supported devices:\n\n");
46 int n = jz_get_num_device_info();
47 for(int i = 0; i < n; ++i) {
48 const jz_device_info* info = jz_get_device_info_indexed(i);
49 printf(" %s - %s\n", info->name, info->description);
50 }
51
52 printf(
53"\n"
54"Available actions for fiiom3k:\n"
55"\n"
56" install --spl <spl.m3k> --bootloader <bootloader.m3k>\n"
57" [--without-backup yes] [--backup IMAGE]\n"
58" Install or update the Rockbox bootloader on a device.\n"
59"\n"
60" If --backup is given, back up the current bootloader to IMAGE before\n"
61" installing the new bootloader. The installer will normally refuse to\n"
62" overwrite your current bootloader; pass '--without-backup yes' if you\n"
63" really want to proceed without taking a backup.\n"
64"\n"
65" WARNING: it is NOT RECOMMENDED to install the Rockbox bootloader\n"
66" without taking a backup of the original firmware bootloader. It may\n"
67" be very difficult or impossible to recover your player without one.\n"
68" At least one M3Ks is known to not to work with the Rockbox bootloader,\n"
69" so it is very important to take a backup.\n"
70"\n"
71" backup --image IMAGE\n"
72" Backup the current bootloader to the file IMAGE\n"
73"\n"
74" restore --image IMAGE\n"
75" Restore a bootloader image backup from the file IMAGE\n"
76"\n");
77
78 exit(4);
79}
80
81void cleanup(void)
82{
83 if(action_params)
84 jz_paramlist_free(action_params);
85 if(jz)
86 jz_context_destroy(jz);
87}
88
89int main(int argc, char** argv)
90{
91 if(argc < 2)
92 usage();
93
94 /* Library initialization */
95 jz = jz_context_create();
96 if(!jz) {
97 fprintf(stderr, "ERROR: Can't create context");
98 return 1;
99 }
100
101 atexit(cleanup);
102 jz_context_set_log_cb(jz, jz_log_cb_stderr);
103 jz_context_set_log_level(jz, JZ_LOG_NOTICE);
104
105 /* Parse global options */
106 --argc, ++argv;
107 while(argc > 0 && argv[0][0] == '-') {
108 if(!strcmp(*argv, "-h") || !strcmp(*argv, "--help"))
109 usage();
110 else if(!strcmp(*argv, "-q") || !strcmp(*argv, "--quiet"))
111 jz_context_set_log_level(jz, JZ_LOG_ERROR);
112 else if(!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose"))
113 jz_context_set_log_level(jz, JZ_LOG_DETAIL);
114 else if(!strcmp(*argv, "-l") || !strcmp(*argv, "--loglevel")) {
115 ++argv;
116 if(--argc == 0) {
117 jz_log(jz, JZ_LOG_ERROR, "Missing argument to option %s", *argv);
118 exit(2);
119 }
120
121 enum jz_log_level level;
122 if(!strcmp(*argv, "ignore"))
123 level = JZ_LOG_IGNORE;
124 else if(!strcmp(*argv, "error"))
125 level = JZ_LOG_ERROR;
126 else if(!strcmp(*argv, "warning"))
127 level = JZ_LOG_WARNING;
128 else if(!strcmp(*argv, "notice"))
129 level = JZ_LOG_NOTICE;
130 else if(!strcmp(*argv, "detail"))
131 level = JZ_LOG_DETAIL;
132 else if(!strcmp(*argv, "debug"))
133 level = JZ_LOG_DEBUG;
134 else {
135 jz_log(jz, JZ_LOG_ERROR, "Invalid log level '%s'", *argv);
136 exit(2);
137 }
138
139 jz_context_set_log_level(jz, level);
140 } else {
141 jz_log(jz, JZ_LOG_ERROR, "Invalid global option '%s'", *argv);
142 exit(2);
143 }
144
145 --argc, ++argv;
146 }
147
148 /* Read the device type */
149 if(argc == 0) {
150 jz_log(jz, JZ_LOG_ERROR, "No device specified (try jztool --help)");
151 exit(2);
152 }
153
154 dev_info = jz_get_device_info_named(*argv);
155 if(!dev_info) {
156 jz_log(jz, JZ_LOG_ERROR, "Unknown device '%s' (try jztool --help)", *argv);
157 exit(2);
158 }
159
160 /* Read the action */
161 --argc, ++argv;
162 if(argc == 0) {
163 jz_log(jz, JZ_LOG_ERROR, "No action specified (try jztool --help)");
164 exit(2);
165 }
166
167 for(dev_action = 0; dev_action < dev_info->num_actions; ++dev_action)
168 if(!strcmp(*argv, dev_info->action_names[dev_action]))
169 break;
170
171 if(dev_action == dev_info->num_actions) {
172 jz_log(jz, JZ_LOG_ERROR, "Unknown action '%s' (try jztool --help)", *argv);
173 exit(2);
174 }
175
176 /* Parse the action options */
177 action_params = jz_paramlist_new();
178 if(!action_params) {
179 jz_log(jz, JZ_LOG_ERROR, "Out of memory: can't create paramlist");
180 exit(1);
181 }
182
183 const char* const* allowed_params = dev_info->action_params[dev_action];
184
185 --argc, ++argv;
186 while(argc > 0 && argv[0][0] == '-') {
187 if(argv[0][1] != '-') {
188 jz_log(jz, JZ_LOG_ERROR, "Invalid option '%s' for action", *argv);
189 exit(2);
190 }
191
192 bool bad_option = true;
193 for(int i = 0; allowed_params[i] != NULL; ++i) {
194 if(!strcmp(&argv[0][2], allowed_params[i])) {
195 ++argv;
196 if(--argc == 0) {
197 jz_log(jz, JZ_LOG_ERROR, "Missing argument for parameter '%s'", *argv);
198 exit(2);
199 }
200
201 int rc = jz_paramlist_set(action_params, allowed_params[i], *argv);
202 if(rc < 0) {
203 jz_log(jz, JZ_LOG_ERROR, "Out of memory");
204 exit(1);
205 }
206
207 bad_option = false;
208 }
209 }
210
211 if(bad_option) {
212 jz_log(jz, JZ_LOG_ERROR, "Invalid option '%s' for action", *argv);
213 exit(2);
214 }
215
216 --argc, ++argv;
217 }
218
219 if(argc != 0) {
220 jz_log(jz, JZ_LOG_ERROR, "Excess arguments on command line");
221 exit(2);
222 }
223
224 /* Invoke action handler */
225 int rc = dev_info->action_funcs[dev_action](jz, action_params);
226 return (rc < 0) ? 1 : 0;
227}