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