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 <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 
42 #ifdef USE_MINGW
43 #include <fcntl.h>
44 #else
45 #include <sys/mman.h>
46 #endif
47 
48 #ifndef __unused
49 #define __unused __attribute__((__unused__))
50 #endif
51 
52 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
53 
54 #define OP_DOWNLOAD   1
55 #define OP_COMMAND    2
56 #define OP_QUERY      3
57 #define OP_NOTICE     4
58 #define OP_DOWNLOAD_SPARSE 5
59 #define OP_WAIT_FOR_DISCONNECT 6
60 
61 typedef struct Action Action;
62 
63 #define CMD_SIZE 64
64 
65 struct Action
66 {
67     unsigned op;
68     Action *next;
69 
70     char cmd[CMD_SIZE];
71     const char *prod;
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 
84 
85 
86 
fb_getvar(struct usb_handle * usb,char * response,const char * fmt,...)87 int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
88 {
89     char cmd[CMD_SIZE] = "getvar:";
90     int getvar_len = strlen(cmd);
91     va_list args;
92 
93     response[FB_RESPONSE_SZ] = '\0';
94     va_start(args, fmt);
95     vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args);
96     va_end(args);
97     cmd[CMD_SIZE - 1] = '\0';
98     return fb_command_response(usb, cmd, response);
99 }
100 
101 
102 /* Return true if this partition is supported by the fastboot format command.
103  * It is also used to determine if we should first erase a partition before
104  * flashing it with an ext4 filesystem.  See needs_erase()
105  *
106  * Not all devices report the filesystem type, so don't report any errors,
107  * just return false.
108  */
fb_format_supported(usb_handle * usb,const char * partition,const char * type_override)109 int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
110 {
111     char fs_type[FB_RESPONSE_SZ + 1] = {0,};
112     int status;
113 
114     if (type_override) {
115         return !!fs_get_generator(type_override);
116     }
117     status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
118     if (status) {
119         return 0;
120     }
121     return !!fs_get_generator(fs_type);
122 }
123 
cb_default(Action * a,int status,char * resp)124 static int cb_default(Action *a, int status, char *resp)
125 {
126     if (status) {
127         fprintf(stderr,"FAILED (%s)\n", resp);
128     } else {
129         double split = now();
130         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
131         a->start = split;
132     }
133     return status;
134 }
135 
queue_action(unsigned op,const char * fmt,...)136 static Action *queue_action(unsigned op, const char *fmt, ...)
137 {
138     Action *a;
139     va_list ap;
140     size_t cmdsize;
141 
142     a = calloc(1, sizeof(Action));
143     if (a == 0) die("out of memory");
144 
145     va_start(ap, fmt);
146     cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
147     va_end(ap);
148 
149     if (cmdsize >= sizeof(a->cmd)) {
150         free(a);
151         die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
152     }
153 
154     if (action_last) {
155         action_last->next = a;
156     } else {
157         action_list = a;
158     }
159     action_last = a;
160     a->op = op;
161     a->func = cb_default;
162 
163     a->start = -1;
164 
165     return a;
166 }
167 
fb_queue_erase(const char * ptn)168 void fb_queue_erase(const char *ptn)
169 {
170     Action *a;
171     a = queue_action(OP_COMMAND, "erase:%s", ptn);
172     a->msg = mkmsg("erasing '%s'", ptn);
173 }
174 
fb_queue_flash(const char * ptn,void * data,unsigned sz)175 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
176 {
177     Action *a;
178 
179     a = queue_action(OP_DOWNLOAD, "");
180     a->data = data;
181     a->size = sz;
182     a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
183 
184     a = queue_action(OP_COMMAND, "flash:%s", ptn);
185     a->msg = mkmsg("writing '%s'", ptn);
186 }
187 
fb_queue_flash_sparse(const char * ptn,struct sparse_file * s,unsigned sz)188 void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz)
189 {
190     Action *a;
191 
192     a = queue_action(OP_DOWNLOAD_SPARSE, "");
193     a->data = s;
194     a->size = 0;
195     a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024);
196 
197     a = queue_action(OP_COMMAND, "flash:%s", ptn);
198     a->msg = mkmsg("writing '%s'", ptn);
199 }
200 
match(char * str,const char ** value,unsigned count)201 static int match(char *str, const char **value, unsigned count)
202 {
203     unsigned n;
204 
205     for (n = 0; n < count; n++) {
206         const char *val = value[n];
207         int len = strlen(val);
208         int match;
209 
210         if ((len > 1) && (val[len-1] == '*')) {
211             len--;
212             match = !strncmp(val, str, len);
213         } else {
214             match = !strcmp(val, str);
215         }
216 
217         if (match) return 1;
218     }
219 
220     return 0;
221 }
222 
223 
224 
cb_check(Action * a,int status,char * resp,int invert)225 static int cb_check(Action *a, int status, char *resp, int invert)
226 {
227     const char **value = a->data;
228     unsigned count = a->size;
229     unsigned n;
230     int yes;
231 
232     if (status) {
233         fprintf(stderr,"FAILED (%s)\n", resp);
234         return status;
235     }
236 
237     if (a->prod) {
238         if (strcmp(a->prod, cur_product) != 0) {
239             double split = now();
240             fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
241                     cur_product, a->prod, (split - a->start));
242             a->start = split;
243             return 0;
244         }
245     }
246 
247     yes = match(resp, value, count);
248     if (invert) yes = !yes;
249 
250     if (yes) {
251         double split = now();
252         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
253         a->start = split;
254         return 0;
255     }
256 
257     fprintf(stderr,"FAILED\n\n");
258     fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
259     fprintf(stderr,"Update %s '%s'",
260             invert ? "rejects" : "requires", value[0]);
261     for (n = 1; n < count; n++) {
262         fprintf(stderr," or '%s'", value[n]);
263     }
264     fprintf(stderr,".\n\n");
265     return -1;
266 }
267 
cb_require(Action * a,int status,char * resp)268 static int cb_require(Action *a, int status, char *resp)
269 {
270     return cb_check(a, status, resp, 0);
271 }
272 
cb_reject(Action * a,int status,char * resp)273 static int cb_reject(Action *a, int status, char *resp)
274 {
275     return cb_check(a, status, resp, 1);
276 }
277 
fb_queue_require(const char * prod,const char * var,int invert,unsigned nvalues,const char ** value)278 void fb_queue_require(const char *prod, const char *var,
279 		int invert, unsigned nvalues, const char **value)
280 {
281     Action *a;
282     a = queue_action(OP_QUERY, "getvar:%s", var);
283     a->prod = prod;
284     a->data = value;
285     a->size = nvalues;
286     a->msg = mkmsg("checking %s", var);
287     a->func = invert ? cb_reject : cb_require;
288     if (a->data == 0) die("out of memory");
289 }
290 
cb_display(Action * a,int status,char * resp)291 static int cb_display(Action *a, int status, char *resp)
292 {
293     if (status) {
294         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
295         return status;
296     }
297     fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
298     return 0;
299 }
300 
fb_queue_display(const char * var,const char * prettyname)301 void fb_queue_display(const char *var, const char *prettyname)
302 {
303     Action *a;
304     a = queue_action(OP_QUERY, "getvar:%s", var);
305     a->data = strdup(prettyname);
306     if (a->data == 0) die("out of memory");
307     a->func = cb_display;
308 }
309 
cb_save(Action * a,int status,char * resp)310 static int cb_save(Action *a, int status, char *resp)
311 {
312     if (status) {
313         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
314         return status;
315     }
316     strncpy(a->data, resp, a->size);
317     return 0;
318 }
319 
fb_queue_query_save(const char * var,char * dest,unsigned dest_size)320 void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
321 {
322     Action *a;
323     a = queue_action(OP_QUERY, "getvar:%s", var);
324     a->data = (void *)dest;
325     a->size = dest_size;
326     a->func = cb_save;
327 }
328 
cb_do_nothing(Action * a __unused,int status __unused,char * resp __unused)329 static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused)
330 {
331     fprintf(stderr,"\n");
332     return 0;
333 }
334 
fb_queue_reboot(void)335 void fb_queue_reboot(void)
336 {
337     Action *a = queue_action(OP_COMMAND, "reboot");
338     a->func = cb_do_nothing;
339     a->msg = "rebooting";
340 }
341 
fb_queue_command(const char * cmd,const char * msg)342 void fb_queue_command(const char *cmd, const char *msg)
343 {
344     Action *a = queue_action(OP_COMMAND, cmd);
345     a->msg = msg;
346 }
347 
fb_queue_download(const char * name,void * data,unsigned size)348 void fb_queue_download(const char *name, void *data, unsigned size)
349 {
350     Action *a = queue_action(OP_DOWNLOAD, "");
351     a->data = data;
352     a->size = size;
353     a->msg = mkmsg("downloading '%s'", name);
354 }
355 
fb_queue_notice(const char * notice)356 void fb_queue_notice(const char *notice)
357 {
358     Action *a = queue_action(OP_NOTICE, "");
359     a->data = (void*) notice;
360 }
361 
fb_queue_wait_for_disconnect(void)362 void fb_queue_wait_for_disconnect(void)
363 {
364     queue_action(OP_WAIT_FOR_DISCONNECT, "");
365 }
366 
fb_execute_queue(usb_handle * usb)367 int fb_execute_queue(usb_handle *usb)
368 {
369     Action *a;
370     char resp[FB_RESPONSE_SZ+1];
371     int status = 0;
372 
373     a = action_list;
374     if (!a)
375         return status;
376     resp[FB_RESPONSE_SZ] = 0;
377 
378     double start = -1;
379     for (a = action_list; a; a = a->next) {
380         a->start = now();
381         if (start < 0) start = a->start;
382         if (a->msg) {
383             // fprintf(stderr,"%30s... ",a->msg);
384             fprintf(stderr,"%s...\n",a->msg);
385         }
386         if (a->op == OP_DOWNLOAD) {
387             status = fb_download_data(usb, a->data, a->size);
388             status = a->func(a, status, status ? fb_get_error() : "");
389             if (status) break;
390         } else if (a->op == OP_COMMAND) {
391             status = fb_command(usb, a->cmd);
392             status = a->func(a, status, status ? fb_get_error() : "");
393             if (status) break;
394         } else if (a->op == OP_QUERY) {
395             status = fb_command_response(usb, a->cmd, resp);
396             status = a->func(a, status, status ? fb_get_error() : resp);
397             if (status) break;
398         } else if (a->op == OP_NOTICE) {
399             fprintf(stderr,"%s\n",(char*)a->data);
400         } else if (a->op == OP_DOWNLOAD_SPARSE) {
401             status = fb_download_data_sparse(usb, a->data);
402             status = a->func(a, status, status ? fb_get_error() : "");
403             if (status) break;
404         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
405             usb_wait_for_disconnect(usb);
406         } else {
407             die("bogus action");
408         }
409     }
410 
411     fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
412     return status;
413 }
414 
fb_queue_is_empty(void)415 int fb_queue_is_empty(void)
416 {
417     return (action_list == NULL);
418 }
419