diff options
Diffstat (limited to 'rbutil/jztool/jztool.c')
-rw-r--r-- | rbutil/jztool/jztool.c | 227 |
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 | |||
28 | jz_context* jz = NULL; | ||
29 | const jz_device_info* dev_info = NULL; | ||
30 | int dev_action = -1; | ||
31 | jz_paramlist* action_params = NULL; | ||
32 | |||
33 | void 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 | |||
81 | void cleanup(void) | ||
82 | { | ||
83 | if(action_params) | ||
84 | jz_paramlist_free(action_params); | ||
85 | if(jz) | ||
86 | jz_context_destroy(jz); | ||
87 | } | ||
88 | |||
89 | int 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 | } | ||