blob: 4c7e197fd825d2dc12ef1e8452e3bd96f4d1280a [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <stdarg.h>
32#include <string.h>
33
34#include "fastboot.h"
35
36char *mkmsg(const char *fmt, ...)
37{
38 char buf[256];
39 char *s;
40 va_list ap;
41
42 va_start(ap, fmt);
43 vsprintf(buf, fmt, ap);
44 va_end(ap);
45
46 s = strdup(buf);
47 if (s == 0) die("out of memory");
48 return s;
49}
50
51#define OP_DOWNLOAD 1
52#define OP_COMMAND 2
53#define OP_QUERY 3
54#define OP_NOTICE 4
55
56typedef struct Action Action;
57
58struct Action
59{
60 unsigned op;
61 Action *next;
62
63 char cmd[64];
64 void *data;
65 unsigned size;
66
67 const char *msg;
68 int (*func)(Action *a, int status, char *resp);
69};
70
71static Action *action_list = 0;
72static Action *action_last = 0;
73
74static int cb_default(Action *a, int status, char *resp)
75{
76 if (status) {
77 fprintf(stderr,"FAILED (%s)\n", resp);
78 } else {
79 fprintf(stderr,"OKAY\n");
80 }
81 return status;
82}
83
84static Action *queue_action(unsigned op, const char *fmt, ...)
85{
86 Action *a;
87 va_list ap;
88
89 a = calloc(1, sizeof(Action));
90 if (a == 0) die("out of memory");
91
92 va_start(ap, fmt);
93 vsprintf(a->cmd, fmt, ap);
94 va_end(ap);
95
96 if (action_last) {
97 action_last->next = a;
98 } else {
99 action_list = a;
100 }
101 action_last = a;
102 a->op = op;
103 a->func = cb_default;
104 return a;
105}
106
107void fb_queue_erase(const char *ptn)
108{
109 Action *a;
110 a = queue_action(OP_COMMAND, "erase:%s", ptn);
111 a->msg = mkmsg("erasing '%s'", ptn);
112}
113
114void fb_queue_flash(const char *ptn, void *data, unsigned sz)
115{
116 Action *a;
117
118 a = queue_action(OP_DOWNLOAD, "");
119 a->data = data;
120 a->size = sz;
121 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
122
123 a = queue_action(OP_COMMAND, "flash:%s", ptn);
124 a->msg = mkmsg("writing '%s'", ptn);
125}
126
127static int match(char *str, const char **value, unsigned count)
128{
129 const char *val;
130 unsigned n;
131 int len;
132
133 for (n = 0; n < count; n++) {
134 const char *val = value[n];
135 int len = strlen(val);
136 int match;
137
138 if ((len > 1) && (val[len-1] == '*')) {
139 len--;
140 match = !strncmp(val, str, len);
141 } else {
142 match = !strcmp(val, str);
143 }
144
145 if (match) return 1;
146 }
147
148 return 0;
149}
150
151
152
153static int cb_check(Action *a, int status, char *resp, int invert)
154{
155 const char **value = a->data;
156 unsigned count = a->size;
157 unsigned n;
158 int yes;
159
160 if (status) {
161 fprintf(stderr,"FAILED (%s)\n", resp);
162 return status;
163 }
164
165 yes = match(resp, value, count);
166 if (invert) yes = !yes;
167
168 if (yes) {
169 fprintf(stderr,"OKAY\n");
170 return 0;
171 }
172
173 fprintf(stderr,"FAILED\n\n");
174 fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
175 fprintf(stderr,"Update %s '%s'",
176 invert ? "rejects" : "requires", value[0]);
177 for (n = 1; n < count; n++) {
178 fprintf(stderr," or '%s'", value[n]);
179 }
180 fprintf(stderr,".\n\n");
181 return -1;
182}
183
184static int cb_require(Action *a, int status, char *resp)
185{
186 return cb_check(a, status, resp, 0);
187}
188
189static int cb_reject(Action *a, int status, char *resp)
190{
191 return cb_check(a, status, resp, 1);
192}
193
194void fb_queue_require(const char *var, int invert, unsigned nvalues, const char **value)
195{
196 Action *a;
197 a = queue_action(OP_QUERY, "getvar:%s", var);
198 a->data = value;
199 a->size = nvalues;
200 a->msg = mkmsg("checking %s", var);
201 a->func = invert ? cb_reject : cb_require;
202 if (a->data == 0) die("out of memory");
203}
204
205static int cb_display(Action *a, int status, char *resp)
206{
207 if (status) {
208 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
209 return status;
210 }
211 fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
212 return 0;
213}
214
215void fb_queue_display(const char *var, const char *prettyname)
216{
217 Action *a;
218 a = queue_action(OP_QUERY, "getvar:%s", var);
219 a->data = strdup(prettyname);
220 if (a->data == 0) die("out of memory");
221 a->func = cb_display;
222}
223
224static int cb_do_nothing(Action *a, int status, char *resp)
225{
226 fprintf(stderr,"\n");
227 return 0;
228}
229
230void fb_queue_reboot(void)
231{
232 Action *a = queue_action(OP_COMMAND, "reboot");
233 a->func = cb_do_nothing;
234 a->msg = "rebooting";
235}
236
237void fb_queue_command(const char *cmd, const char *msg)
238{
239 Action *a = queue_action(OP_COMMAND, cmd);
240 a->msg = msg;
241}
242
243void fb_queue_download(const char *name, void *data, unsigned size)
244{
245 Action *a = queue_action(OP_DOWNLOAD, "");
246 a->data = data;
247 a->size = size;
248 a->msg = mkmsg("downloading '%s'", name);
249}
250
251void fb_queue_notice(const char *notice)
252{
253 Action *a = queue_action(OP_NOTICE, "");
254 a->data = (void*) notice;
255}
256
257void fb_execute_queue(usb_handle *usb)
258{
259 Action *a;
260 char resp[FB_RESPONSE_SZ+1];
261 int status;
262
263 a = action_list;
264 resp[FB_RESPONSE_SZ] = 0;
265
266 for (a = action_list; a; a = a->next) {
267 if (a->msg) {
268 fprintf(stderr,"%s... ",a->msg);
269 }
270 if (a->op == OP_DOWNLOAD) {
271 status = fb_download_data(usb, a->data, a->size);
272 status = a->func(a, status, status ? fb_get_error() : "");
273 if (status) break;
274 } else if (a->op == OP_COMMAND) {
275 status = fb_command(usb, a->cmd);
276 status = a->func(a, status, status ? fb_get_error() : "");
277 if (status) break;
278 } else if (a->op == OP_QUERY) {
279 status = fb_command_response(usb, a->cmd, resp);
280 status = a->func(a, status, status ? fb_get_error() : resp);
281 if (status) break;
282 } else if (a->op == OP_NOTICE) {
283 fprintf(stderr,"%s\n",(char*)a->data);
284 } else {
285 die("bogus action");
286 }
287 }
288}
289