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 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 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 const char *prod; 73 void *data; 74 unsigned size; 75 76 const char *msg; 77 int (*func)(Action *a, int status, char *resp); 78 79 double start; 80 }; 81 82 static Action *action_list = 0; 83 static Action *action_last = 0; 84 85 static int cb_default(Action *a, int status, char *resp) 86 { 87 if (status) { 88 fprintf(stderr,"FAILED (%s)\n", resp); 89 } else { 90 double split = now(); 91 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start)); 92 a->start = split; 93 } 94 return status; 95 } 96 97 static Action *queue_action(unsigned op, const char *fmt, ...) 98 { 99 Action *a; 100 va_list ap; 101 size_t cmdsize; 102 103 a = calloc(1, sizeof(Action)); 104 if (a == 0) die("out of memory"); 105 106 va_start(ap, fmt); 107 cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap); 108 va_end(ap); 109 110 if (cmdsize >= sizeof(a->cmd)) { 111 free(a); 112 die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd)); 113 } 114 115 if (action_last) { 116 action_last->next = a; 117 } else { 118 action_list = a; 119 } 120 action_last = a; 121 a->op = op; 122 a->func = cb_default; 123 124 a->start = -1; 125 126 return a; 127 } 128 129 void fb_queue_erase(const char *ptn) 130 { 131 Action *a; 132 a = queue_action(OP_COMMAND, "erase:%s", ptn); 133 a->msg = mkmsg("erasing '%s'", ptn); 134 } 135 136 void fb_queue_flash(const char *ptn, void *data, unsigned sz) 137 { 138 Action *a; 139 140 a = queue_action(OP_DOWNLOAD, ""); 141 a->data = data; 142 a->size = sz; 143 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024); 144 145 a = queue_action(OP_COMMAND, "flash:%s", ptn); 146 a->msg = mkmsg("writing '%s'", ptn); 147 } 148 149 static int match(char *str, const char **value, unsigned count) 150 { 151 const char *val; 152 unsigned n; 153 int len; 154 155 for (n = 0; n < count; n++) { 156 const char *val = value[n]; 157 int len = strlen(val); 158 int match; 159 160 if ((len > 1) && (val[len-1] == '*')) { 161 len--; 162 match = !strncmp(val, str, len); 163 } else { 164 match = !strcmp(val, str); 165 } 166 167 if (match) return 1; 168 } 169 170 return 0; 171 } 172 173 174 175 static int cb_check(Action *a, int status, char *resp, int invert) 176 { 177 const char **value = a->data; 178 unsigned count = a->size; 179 unsigned n; 180 int yes; 181 182 if (status) { 183 fprintf(stderr,"FAILED (%s)\n", resp); 184 return status; 185 } 186 187 if (a->prod) { 188 if (strcmp(a->prod, cur_product) != 0) { 189 double split = now(); 190 fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n", 191 cur_product, a->prod, (split - a->start)); 192 a->start = split; 193 return 0; 194 } 195 } 196 197 yes = match(resp, value, count); 198 if (invert) yes = !yes; 199 200 if (yes) { 201 double split = now(); 202 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start)); 203 a->start = split; 204 return 0; 205 } 206 207 fprintf(stderr,"FAILED\n\n"); 208 fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp); 209 fprintf(stderr,"Update %s '%s'", 210 invert ? "rejects" : "requires", value[0]); 211 for (n = 1; n < count; n++) { 212 fprintf(stderr," or '%s'", value[n]); 213 } 214 fprintf(stderr,".\n\n"); 215 return -1; 216 } 217 218 static int cb_require(Action *a, int status, char *resp) 219 { 220 return cb_check(a, status, resp, 0); 221 } 222 223 static int cb_reject(Action *a, int status, char *resp) 224 { 225 return cb_check(a, status, resp, 1); 226 } 227 228 void fb_queue_require(const char *prod, const char *var, 229 int invert, unsigned nvalues, const char **value) 230 { 231 Action *a; 232 a = queue_action(OP_QUERY, "getvar:%s", var); 233 a->prod = prod; 234 a->data = value; 235 a->size = nvalues; 236 a->msg = mkmsg("checking %s", var); 237 a->func = invert ? cb_reject : cb_require; 238 if (a->data == 0) die("out of memory"); 239 } 240 241 static int cb_display(Action *a, int status, char *resp) 242 { 243 if (status) { 244 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp); 245 return status; 246 } 247 fprintf(stderr, "%s: %s\n", (char*) a->data, resp); 248 return 0; 249 } 250 251 void fb_queue_display(const char *var, const char *prettyname) 252 { 253 Action *a; 254 a = queue_action(OP_QUERY, "getvar:%s", var); 255 a->data = strdup(prettyname); 256 if (a->data == 0) die("out of memory"); 257 a->func = cb_display; 258 } 259 260 static int cb_save(Action *a, int status, char *resp) 261 { 262 if (status) { 263 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp); 264 return status; 265 } 266 strncpy(a->data, resp, a->size); 267 return 0; 268 } 269 270 void fb_queue_query_save(const char *var, char *dest, unsigned dest_size) 271 { 272 Action *a; 273 a = queue_action(OP_QUERY, "getvar:%s", var); 274 a->data = (void *)dest; 275 a->size = dest_size; 276 a->func = cb_save; 277 } 278 279 static int cb_do_nothing(Action *a, int status, char *resp) 280 { 281 fprintf(stderr,"\n"); 282 return 0; 283 } 284 285 void fb_queue_reboot(void) 286 { 287 Action *a = queue_action(OP_COMMAND, "reboot"); 288 a->func = cb_do_nothing; 289 a->msg = "rebooting"; 290 } 291 292 void fb_queue_command(const char *cmd, const char *msg) 293 { 294 Action *a = queue_action(OP_COMMAND, cmd); 295 a->msg = msg; 296 } 297 298 void fb_queue_download(const char *name, void *data, unsigned size) 299 { 300 Action *a = queue_action(OP_DOWNLOAD, ""); 301 a->data = data; 302 a->size = size; 303 a->msg = mkmsg("downloading '%s'", name); 304 } 305 306 void fb_queue_notice(const char *notice) 307 { 308 Action *a = queue_action(OP_NOTICE, ""); 309 a->data = (void*) notice; 310 } 311 312 int fb_execute_queue(usb_handle *usb) 313 { 314 Action *a; 315 char resp[FB_RESPONSE_SZ+1]; 316 int status = 0; 317 318 a = action_list; 319 resp[FB_RESPONSE_SZ] = 0; 320 321 double start = -1; 322 for (a = action_list; a; a = a->next) { 323 a->start = now(); 324 if (start < 0) start = a->start; 325 if (a->msg) { 326 // fprintf(stderr,"%30s... ",a->msg); 327 fprintf(stderr,"%s...\n",a->msg); 328 } 329 if (a->op == OP_DOWNLOAD) { 330 status = fb_download_data(usb, a->data, a->size); 331 status = a->func(a, status, status ? fb_get_error() : ""); 332 if (status) break; 333 } else if (a->op == OP_COMMAND) { 334 status = fb_command(usb, a->cmd); 335 status = a->func(a, status, status ? fb_get_error() : ""); 336 if (status) break; 337 } else if (a->op == OP_QUERY) { 338 status = fb_command_response(usb, a->cmd, resp); 339 status = a->func(a, status, status ? fb_get_error() : resp); 340 if (status) break; 341 } else if (a->op == OP_NOTICE) { 342 fprintf(stderr,"%s\n",(char*)a->data); 343 } else { 344 die("bogus action"); 345 } 346 } 347 348 fprintf(stderr,"finished. total time: %.3fs\n", (now() - start)); 349 return status; 350 } 351