Home | History | Annotate | Download | only in fastboot
      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