• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #include <sys/time.h>
34 
35 #include "fastboot.h"
36 
now()37 double now()
38 {
39     struct timeval tv;
40     gettimeofday(&tv, NULL);
41     return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
42 }
43 
mkmsg(const char * fmt,...)44 char *mkmsg(const char *fmt, ...)
45 {
46     char buf[256];
47     char *s;
48     va_list ap;
49 
50     va_start(ap, fmt);
51     vsprintf(buf, fmt, ap);
52     va_end(ap);
53 
54     s = strdup(buf);
55     if (s == 0) die("out of memory");
56     return s;
57 }
58 
59 #define OP_DOWNLOAD   1
60 #define OP_COMMAND    2
61 #define OP_QUERY      3
62 #define OP_NOTICE     4
63 
64 typedef struct Action Action;
65 
66 struct Action
67 {
68     unsigned op;
69     Action *next;
70 
71     char cmd[64];
72     void *data;
73     unsigned size;
74 
75     const char *msg;
76     int (*func)(Action *a, int status, char *resp);
77 
78     double start;
79 };
80 
81 static Action *action_list = 0;
82 static Action *action_last = 0;
83 
cb_default(Action * a,int status,char * resp)84 static int cb_default(Action *a, int status, char *resp)
85 {
86     if (status) {
87         fprintf(stderr,"FAILED (%s)\n", resp);
88     } else {
89         double split = now();
90         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
91         a->start = split;
92     }
93     return status;
94 }
95 
queue_action(unsigned op,const char * fmt,...)96 static Action *queue_action(unsigned op, const char *fmt, ...)
97 {
98     Action *a;
99     va_list ap;
100 
101     a = calloc(1, sizeof(Action));
102     if (a == 0) die("out of memory");
103 
104     va_start(ap, fmt);
105     vsprintf(a->cmd, fmt, ap);
106     va_end(ap);
107 
108     if (action_last) {
109         action_last->next = a;
110     } else {
111         action_list = a;
112     }
113     action_last = a;
114     a->op = op;
115     a->func = cb_default;
116 
117     a->start = -1;
118 
119     return a;
120 }
121 
fb_queue_erase(const char * ptn)122 void fb_queue_erase(const char *ptn)
123 {
124     Action *a;
125     a = queue_action(OP_COMMAND, "erase:%s", ptn);
126     a->msg = mkmsg("erasing '%s'", ptn);
127 }
128 
fb_queue_flash(const char * ptn,void * data,unsigned sz)129 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
130 {
131     Action *a;
132 
133     a = queue_action(OP_DOWNLOAD, "");
134     a->data = data;
135     a->size = sz;
136     a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
137 
138     a = queue_action(OP_COMMAND, "flash:%s", ptn);
139     a->msg = mkmsg("writing '%s'", ptn);
140 }
141 
match(char * str,const char ** value,unsigned count)142 static int match(char *str, const char **value, unsigned count)
143 {
144     const char *val;
145     unsigned n;
146     int len;
147 
148     for (n = 0; n < count; n++) {
149         const char *val = value[n];
150         int len = strlen(val);
151         int match;
152 
153         if ((len > 1) && (val[len-1] == '*')) {
154             len--;
155             match = !strncmp(val, str, len);
156         } else {
157             match = !strcmp(val, str);
158         }
159 
160         if (match) return 1;
161     }
162 
163     return 0;
164 }
165 
166 
167 
cb_check(Action * a,int status,char * resp,int invert)168 static int cb_check(Action *a, int status, char *resp, int invert)
169 {
170     const char **value = a->data;
171     unsigned count = a->size;
172     unsigned n;
173     int yes;
174 
175     if (status) {
176         fprintf(stderr,"FAILED (%s)\n", resp);
177         return status;
178     }
179 
180     yes = match(resp, value, count);
181     if (invert) yes = !yes;
182 
183     if (yes) {
184         double split = now();
185         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
186         a->start = split;
187         return 0;
188     }
189 
190     fprintf(stderr,"FAILED\n\n");
191     fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
192     fprintf(stderr,"Update %s '%s'",
193             invert ? "rejects" : "requires", value[0]);
194     for (n = 1; n < count; n++) {
195         fprintf(stderr," or '%s'", value[n]);
196     }
197     fprintf(stderr,".\n\n");
198     return -1;
199 }
200 
cb_require(Action * a,int status,char * resp)201 static int cb_require(Action *a, int status, char *resp)
202 {
203     return cb_check(a, status, resp, 0);
204 }
205 
cb_reject(Action * a,int status,char * resp)206 static int cb_reject(Action *a, int status, char *resp)
207 {
208     return cb_check(a, status, resp, 1);
209 }
210 
fb_queue_require(const char * var,int invert,unsigned nvalues,const char ** value)211 void fb_queue_require(const char *var, int invert, unsigned nvalues, const char **value)
212 {
213     Action *a;
214     a = queue_action(OP_QUERY, "getvar:%s", var);
215     a->data = value;
216     a->size = nvalues;
217     a->msg = mkmsg("checking %s", var);
218     a->func = invert ? cb_reject : cb_require;
219     if (a->data == 0) die("out of memory");
220 }
221 
cb_display(Action * a,int status,char * resp)222 static int cb_display(Action *a, int status, char *resp)
223 {
224     if (status) {
225         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
226         return status;
227     }
228     fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
229     return 0;
230 }
231 
fb_queue_display(const char * var,const char * prettyname)232 void fb_queue_display(const char *var, const char *prettyname)
233 {
234     Action *a;
235     a = queue_action(OP_QUERY, "getvar:%s", var);
236     a->data = strdup(prettyname);
237     if (a->data == 0) die("out of memory");
238     a->func = cb_display;
239 }
240 
cb_do_nothing(Action * a,int status,char * resp)241 static int cb_do_nothing(Action *a, int status, char *resp)
242 {
243     fprintf(stderr,"\n");
244     return 0;
245 }
246 
fb_queue_reboot(void)247 void fb_queue_reboot(void)
248 {
249     Action *a = queue_action(OP_COMMAND, "reboot");
250     a->func = cb_do_nothing;
251     a->msg = "rebooting";
252 }
253 
fb_queue_command(const char * cmd,const char * msg)254 void fb_queue_command(const char *cmd, const char *msg)
255 {
256     Action *a = queue_action(OP_COMMAND, cmd);
257     a->msg = msg;
258 }
259 
fb_queue_download(const char * name,void * data,unsigned size)260 void fb_queue_download(const char *name, void *data, unsigned size)
261 {
262     Action *a = queue_action(OP_DOWNLOAD, "");
263     a->data = data;
264     a->size = size;
265     a->msg = mkmsg("downloading '%s'", name);
266 }
267 
fb_queue_notice(const char * notice)268 void fb_queue_notice(const char *notice)
269 {
270     Action *a = queue_action(OP_NOTICE, "");
271     a->data = (void*) notice;
272 }
273 
fb_execute_queue(usb_handle * usb)274 void fb_execute_queue(usb_handle *usb)
275 {
276     Action *a;
277     char resp[FB_RESPONSE_SZ+1];
278     int status;
279 
280     a = action_list;
281     resp[FB_RESPONSE_SZ] = 0;
282 
283     double start = -1;
284     for (a = action_list; a; a = a->next) {
285         a->start = now();
286         if (start < 0) start = a->start;
287         if (a->msg) {
288             // fprintf(stderr,"%30s... ",a->msg);
289             fprintf(stderr,"%s...\n",a->msg);
290         }
291         if (a->op == OP_DOWNLOAD) {
292             status = fb_download_data(usb, a->data, a->size);
293             status = a->func(a, status, status ? fb_get_error() : "");
294             if (status) break;
295         } else if (a->op == OP_COMMAND) {
296             status = fb_command(usb, a->cmd);
297             status = a->func(a, status, status ? fb_get_error() : "");
298             if (status) break;
299         } else if (a->op == OP_QUERY) {
300             status = fb_command_response(usb, a->cmd, resp);
301             status = a->func(a, status, status ? fb_get_error() : resp);
302             if (status) break;
303         } else if (a->op == OP_NOTICE) {
304             fprintf(stderr,"%s\n",(char*)a->data);
305         } else {
306             die("bogus action");
307         }
308     }
309 
310     fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
311 }
312 
313