• 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 "fastboot.h"
30 #include "fs.h"
31 
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 
41 #define OP_DOWNLOAD   1
42 #define OP_COMMAND    2
43 #define OP_QUERY      3
44 #define OP_NOTICE     4
45 #define OP_DOWNLOAD_SPARSE 5
46 #define OP_WAIT_FOR_DISCONNECT 6
47 
48 typedef struct Action Action;
49 
50 #define CMD_SIZE 64
51 
52 struct Action {
53     unsigned op;
54     Action* next;
55 
56     char cmd[CMD_SIZE];
57     const char* prod;
58     void* data;
59 
60     // The protocol only supports 32-bit sizes, so you'll have to break
61     // anything larger into chunks.
62     uint32_t size;
63 
64     const char *msg;
65     int (*func)(Action* a, int status, const char* resp);
66 
67     double start;
68 };
69 
70 static Action *action_list = 0;
71 static Action *action_last = 0;
72 
73 
74 
75 
fb_getvar(Transport * transport,const std::string & key,std::string * value)76 bool fb_getvar(Transport* transport, const std::string& key, std::string* value) {
77     std::string cmd = "getvar:";
78     cmd += key;
79 
80     char buf[FB_RESPONSE_SZ + 1];
81     memset(buf, 0, sizeof(buf));
82     if (fb_command_response(transport, cmd.c_str(), buf)) {
83       return false;
84     }
85     *value = buf;
86     return true;
87 }
88 
cb_default(Action * a,int status,const char * resp)89 static int cb_default(Action* a, int status, const char* resp) {
90     if (status) {
91         fprintf(stderr,"FAILED (%s)\n", resp);
92     } else {
93         double split = now();
94         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
95         a->start = split;
96     }
97     return status;
98 }
99 
queue_action(unsigned op,const char * fmt,...)100 static Action *queue_action(unsigned op, const char *fmt, ...)
101 {
102     va_list ap;
103     size_t cmdsize;
104 
105     Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
106     if (a == nullptr) die("out of memory");
107 
108     va_start(ap, fmt);
109     cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
110     va_end(ap);
111 
112     if (cmdsize >= sizeof(a->cmd)) {
113         free(a);
114         die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
115     }
116 
117     if (action_last) {
118         action_last->next = a;
119     } else {
120         action_list = a;
121     }
122     action_last = a;
123     a->op = op;
124     a->func = cb_default;
125 
126     a->start = -1;
127 
128     return a;
129 }
130 
fb_set_active(const char * slot)131 void fb_set_active(const char *slot)
132 {
133     Action *a;
134     a = queue_action(OP_COMMAND, "set_active:%s", slot);
135     a->msg = mkmsg("Setting current slot to '%s'", slot);
136 }
137 
fb_queue_erase(const char * ptn)138 void fb_queue_erase(const char *ptn)
139 {
140     Action *a;
141     a = queue_action(OP_COMMAND, "erase:%s", ptn);
142     a->msg = mkmsg("erasing '%s'", ptn);
143 }
144 
fb_queue_flash(const char * ptn,void * data,unsigned sz)145 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
146 {
147     Action *a;
148 
149     a = queue_action(OP_DOWNLOAD, "");
150     a->data = data;
151     a->size = sz;
152     a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
153 
154     a = queue_action(OP_COMMAND, "flash:%s", ptn);
155     a->msg = mkmsg("writing '%s'", ptn);
156 }
157 
fb_queue_flash_sparse(const char * ptn,struct sparse_file * s,unsigned sz,size_t current,size_t total)158 void fb_queue_flash_sparse(const char* ptn, struct sparse_file* s, unsigned sz, size_t current,
159                            size_t total) {
160     Action *a;
161 
162     a = queue_action(OP_DOWNLOAD_SPARSE, "");
163     a->data = s;
164     a->size = 0;
165     a->msg = mkmsg("sending sparse '%s' %zu/%zu (%d KB)", ptn, current, total, sz / 1024);
166 
167     a = queue_action(OP_COMMAND, "flash:%s", ptn);
168     a->msg = mkmsg("writing '%s' %zu/%zu", ptn, current, total);
169 }
170 
match(const char * str,const char ** value,unsigned count)171 static int match(const char* str, const char** value, unsigned count) {
172     unsigned n;
173 
174     for (n = 0; n < count; n++) {
175         const char *val = value[n];
176         int len = strlen(val);
177         int match;
178 
179         if ((len > 1) && (val[len-1] == '*')) {
180             len--;
181             match = !strncmp(val, str, len);
182         } else {
183             match = !strcmp(val, str);
184         }
185 
186         if (match) return 1;
187     }
188 
189     return 0;
190 }
191 
192 
193 
cb_check(Action * a,int status,const char * resp,int invert)194 static int cb_check(Action* a, int status, const char* resp, int invert)
195 {
196     const char** value = reinterpret_cast<const char**>(a->data);
197     unsigned count = a->size;
198     unsigned n;
199     int yes;
200 
201     if (status) {
202         fprintf(stderr,"FAILED (%s)\n", resp);
203         return status;
204     }
205 
206     if (a->prod) {
207         if (strcmp(a->prod, cur_product) != 0) {
208             double split = now();
209             fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
210                     cur_product, a->prod, (split - a->start));
211             a->start = split;
212             return 0;
213         }
214     }
215 
216     yes = match(resp, value, count);
217     if (invert) yes = !yes;
218 
219     if (yes) {
220         double split = now();
221         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
222         a->start = split;
223         return 0;
224     }
225 
226     fprintf(stderr,"FAILED\n\n");
227     fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
228     fprintf(stderr,"Update %s '%s'",
229             invert ? "rejects" : "requires", value[0]);
230     for (n = 1; n < count; n++) {
231         fprintf(stderr," or '%s'", value[n]);
232     }
233     fprintf(stderr,".\n\n");
234     return -1;
235 }
236 
cb_require(Action * a,int status,const char * resp)237 static int cb_require(Action*a, int status, const char* resp) {
238     return cb_check(a, status, resp, 0);
239 }
240 
cb_reject(Action * a,int status,const char * resp)241 static int cb_reject(Action* a, int status, const char* resp) {
242     return cb_check(a, status, resp, 1);
243 }
244 
fb_queue_require(const char * prod,const char * var,bool invert,size_t nvalues,const char ** value)245 void fb_queue_require(const char *prod, const char *var,
246                       bool invert, size_t nvalues, const char **value)
247 {
248     Action *a;
249     a = queue_action(OP_QUERY, "getvar:%s", var);
250     a->prod = prod;
251     a->data = value;
252     a->size = nvalues;
253     a->msg = mkmsg("checking %s", var);
254     a->func = invert ? cb_reject : cb_require;
255     if (a->data == nullptr) die("out of memory");
256 }
257 
cb_display(Action * a,int status,const char * resp)258 static int cb_display(Action* a, int status, const char* resp) {
259     if (status) {
260         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
261         return status;
262     }
263     fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
264     return 0;
265 }
266 
fb_queue_display(const char * var,const char * prettyname)267 void fb_queue_display(const char *var, const char *prettyname)
268 {
269     Action *a;
270     a = queue_action(OP_QUERY, "getvar:%s", var);
271     a->data = strdup(prettyname);
272     if (a->data == nullptr) die("out of memory");
273     a->func = cb_display;
274 }
275 
cb_save(Action * a,int status,const char * resp)276 static int cb_save(Action* a, int status, const char* resp) {
277     if (status) {
278         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
279         return status;
280     }
281     strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
282     return 0;
283 }
284 
fb_queue_query_save(const char * var,char * dest,unsigned dest_size)285 void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
286 {
287     Action *a;
288     a = queue_action(OP_QUERY, "getvar:%s", var);
289     a->data = (void *)dest;
290     a->size = dest_size;
291     a->func = cb_save;
292 }
293 
cb_do_nothing(Action *,int,const char *)294 static int cb_do_nothing(Action*, int , const char*) {
295     fprintf(stderr,"\n");
296     return 0;
297 }
298 
fb_queue_reboot(void)299 void fb_queue_reboot(void)
300 {
301     Action *a = queue_action(OP_COMMAND, "reboot");
302     a->func = cb_do_nothing;
303     a->msg = "rebooting";
304 }
305 
fb_queue_command(const char * cmd,const char * msg)306 void fb_queue_command(const char *cmd, const char *msg)
307 {
308     Action *a = queue_action(OP_COMMAND, cmd);
309     a->msg = msg;
310 }
311 
fb_queue_download(const char * name,void * data,unsigned size)312 void fb_queue_download(const char *name, void *data, unsigned size)
313 {
314     Action *a = queue_action(OP_DOWNLOAD, "");
315     a->data = data;
316     a->size = size;
317     a->msg = mkmsg("downloading '%s'", name);
318 }
319 
fb_queue_notice(const char * notice)320 void fb_queue_notice(const char *notice)
321 {
322     Action *a = queue_action(OP_NOTICE, "");
323     a->data = (void*) notice;
324 }
325 
fb_queue_wait_for_disconnect(void)326 void fb_queue_wait_for_disconnect(void)
327 {
328     queue_action(OP_WAIT_FOR_DISCONNECT, "");
329 }
330 
fb_execute_queue(Transport * transport)331 int fb_execute_queue(Transport* transport)
332 {
333     Action *a;
334     char resp[FB_RESPONSE_SZ+1];
335     int status = 0;
336 
337     a = action_list;
338     if (!a)
339         return status;
340     resp[FB_RESPONSE_SZ] = 0;
341 
342     double start = -1;
343     for (a = action_list; a; a = a->next) {
344         a->start = now();
345         if (start < 0) start = a->start;
346         if (a->msg) {
347             // fprintf(stderr,"%30s... ",a->msg);
348             fprintf(stderr,"%s...\n",a->msg);
349         }
350         if (a->op == OP_DOWNLOAD) {
351             status = fb_download_data(transport, a->data, a->size);
352             status = a->func(a, status, status ? fb_get_error().c_str() : "");
353             if (status) break;
354         } else if (a->op == OP_COMMAND) {
355             status = fb_command(transport, a->cmd);
356             status = a->func(a, status, status ? fb_get_error().c_str() : "");
357             if (status) break;
358         } else if (a->op == OP_QUERY) {
359             status = fb_command_response(transport, a->cmd, resp);
360             status = a->func(a, status, status ? fb_get_error().c_str() : resp);
361             if (status) break;
362         } else if (a->op == OP_NOTICE) {
363             fprintf(stderr,"%s\n",(char*)a->data);
364         } else if (a->op == OP_DOWNLOAD_SPARSE) {
365             status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
366             status = a->func(a, status, status ? fb_get_error().c_str() : "");
367             if (status) break;
368         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
369             transport->WaitForDisconnect();
370         } else {
371             die("bogus action");
372         }
373     }
374 
375     fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
376     return status;
377 }
378