• 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 
34 #include "fastboot.h"
35 
mkmsg(const char * fmt,...)36 char *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 
56 typedef struct Action Action;
57 
58 struct 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 
71 static Action *action_list = 0;
72 static Action *action_last = 0;
73 
cb_default(Action * a,int status,char * resp)74 static 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 
queue_action(unsigned op,const char * fmt,...)84 static 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 
fb_queue_erase(const char * ptn)107 void 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 
fb_queue_flash(const char * ptn,void * data,unsigned sz)114 void 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 
match(char * str,const char ** value,unsigned count)127 static 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 
cb_check(Action * a,int status,char * resp,int invert)153 static 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 
cb_require(Action * a,int status,char * resp)184 static int cb_require(Action *a, int status, char *resp)
185 {
186     return cb_check(a, status, resp, 0);
187 }
188 
cb_reject(Action * a,int status,char * resp)189 static int cb_reject(Action *a, int status, char *resp)
190 {
191     return cb_check(a, status, resp, 1);
192 }
193 
fb_queue_require(const char * var,int invert,unsigned nvalues,const char ** value)194 void 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 
cb_display(Action * a,int status,char * resp)205 static 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 
fb_queue_display(const char * var,const char * prettyname)215 void 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 
cb_do_nothing(Action * a,int status,char * resp)224 static int cb_do_nothing(Action *a, int status, char *resp)
225 {
226     fprintf(stderr,"\n");
227     return 0;
228 }
229 
fb_queue_reboot(void)230 void 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 
fb_queue_command(const char * cmd,const char * msg)237 void fb_queue_command(const char *cmd, const char *msg)
238 {
239     Action *a = queue_action(OP_COMMAND, cmd);
240     a->msg = msg;
241 }
242 
fb_queue_download(const char * name,void * data,unsigned size)243 void 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 
fb_queue_notice(const char * notice)251 void fb_queue_notice(const char *notice)
252 {
253     Action *a = queue_action(OP_NOTICE, "");
254     a->data = (void*) notice;
255 }
256 
fb_execute_queue(usb_handle * usb)257 void 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 
290