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