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