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 <stdbool.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 #include <sys/stat.h>
     39 #include <sys/types.h>
     40 #include <unistd.h>
     41 
     42 #ifdef USE_MINGW
     43 #include <fcntl.h>
     44 #else
     45 #include <sys/mman.h>
     46 #endif
     47 
     48 #ifndef __unused
     49 #define __unused __attribute__((__unused__))
     50 #endif
     51 
     52 #define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
     53 
     54 #define OP_DOWNLOAD   1
     55 #define OP_COMMAND    2
     56 #define OP_QUERY      3
     57 #define OP_NOTICE     4
     58 #define OP_DOWNLOAD_SPARSE 5
     59 #define OP_WAIT_FOR_DISCONNECT 6
     60 
     61 typedef struct Action Action;
     62 
     63 #define CMD_SIZE 64
     64 
     65 struct Action
     66 {
     67     unsigned op;
     68     Action *next;
     69 
     70     char cmd[CMD_SIZE];
     71     const char *prod;
     72     void *data;
     73     unsigned size;
     74 
     75     const char *msg;
     76     int (*func)(Action *a, int status, char *resp);
     77 
     78     double start;
     79 };
     80 
     81 static Action *action_list = 0;
     82 static Action *action_last = 0;
     83 
     84 
     85 
     86 
     87 int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
     88 {
     89     char cmd[CMD_SIZE] = "getvar:";
     90     int getvar_len = strlen(cmd);
     91     va_list args;
     92 
     93     response[FB_RESPONSE_SZ] = '\0';
     94     va_start(args, fmt);
     95     vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args);
     96     va_end(args);
     97     cmd[CMD_SIZE - 1] = '\0';
     98     return fb_command_response(usb, cmd, response);
     99 }
    100 
    101 
    102 /* Return true if this partition is supported by the fastboot format command.
    103  * It is also used to determine if we should first erase a partition before
    104  * flashing it with an ext4 filesystem.  See needs_erase()
    105  *
    106  * Not all devices report the filesystem type, so don't report any errors,
    107  * just return false.
    108  */
    109 int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
    110 {
    111     char fs_type[FB_RESPONSE_SZ + 1] = {0,};
    112     int status;
    113 
    114     if (type_override) {
    115         return !!fs_get_generator(type_override);
    116     }
    117     status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
    118     if (status) {
    119         return 0;
    120     }
    121     return !!fs_get_generator(fs_type);
    122 }
    123 
    124 static int cb_default(Action *a, int status, char *resp)
    125 {
    126     if (status) {
    127         fprintf(stderr,"FAILED (%s)\n", resp);
    128     } else {
    129         double split = now();
    130         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
    131         a->start = split;
    132     }
    133     return status;
    134 }
    135 
    136 static Action *queue_action(unsigned op, const char *fmt, ...)
    137 {
    138     Action *a;
    139     va_list ap;
    140     size_t cmdsize;
    141 
    142     a = calloc(1, sizeof(Action));
    143     if (a == 0) die("out of memory");
    144 
    145     va_start(ap, fmt);
    146     cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
    147     va_end(ap);
    148 
    149     if (cmdsize >= sizeof(a->cmd)) {
    150         free(a);
    151         die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
    152     }
    153 
    154     if (action_last) {
    155         action_last->next = a;
    156     } else {
    157         action_list = a;
    158     }
    159     action_last = a;
    160     a->op = op;
    161     a->func = cb_default;
    162 
    163     a->start = -1;
    164 
    165     return a;
    166 }
    167 
    168 void fb_queue_erase(const char *ptn)
    169 {
    170     Action *a;
    171     a = queue_action(OP_COMMAND, "erase:%s", ptn);
    172     a->msg = mkmsg("erasing '%s'", ptn);
    173 }
    174 
    175 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
    176 {
    177     Action *a;
    178 
    179     a = queue_action(OP_DOWNLOAD, "");
    180     a->data = data;
    181     a->size = sz;
    182     a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
    183 
    184     a = queue_action(OP_COMMAND, "flash:%s", ptn);
    185     a->msg = mkmsg("writing '%s'", ptn);
    186 }
    187 
    188 void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz)
    189 {
    190     Action *a;
    191 
    192     a = queue_action(OP_DOWNLOAD_SPARSE, "");
    193     a->data = s;
    194     a->size = 0;
    195     a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024);
    196 
    197     a = queue_action(OP_COMMAND, "flash:%s", ptn);
    198     a->msg = mkmsg("writing '%s'", ptn);
    199 }
    200 
    201 static int match(char *str, const char **value, unsigned count)
    202 {
    203     unsigned n;
    204 
    205     for (n = 0; n < count; n++) {
    206         const char *val = value[n];
    207         int len = strlen(val);
    208         int match;
    209 
    210         if ((len > 1) && (val[len-1] == '*')) {
    211             len--;
    212             match = !strncmp(val, str, len);
    213         } else {
    214             match = !strcmp(val, str);
    215         }
    216 
    217         if (match) return 1;
    218     }
    219 
    220     return 0;
    221 }
    222 
    223 
    224 
    225 static int cb_check(Action *a, int status, char *resp, int invert)
    226 {
    227     const char **value = a->data;
    228     unsigned count = a->size;
    229     unsigned n;
    230     int yes;
    231 
    232     if (status) {
    233         fprintf(stderr,"FAILED (%s)\n", resp);
    234         return status;
    235     }
    236 
    237     if (a->prod) {
    238         if (strcmp(a->prod, cur_product) != 0) {
    239             double split = now();
    240             fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
    241                     cur_product, a->prod, (split - a->start));
    242             a->start = split;
    243             return 0;
    244         }
    245     }
    246 
    247     yes = match(resp, value, count);
    248     if (invert) yes = !yes;
    249 
    250     if (yes) {
    251         double split = now();
    252         fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
    253         a->start = split;
    254         return 0;
    255     }
    256 
    257     fprintf(stderr,"FAILED\n\n");
    258     fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
    259     fprintf(stderr,"Update %s '%s'",
    260             invert ? "rejects" : "requires", value[0]);
    261     for (n = 1; n < count; n++) {
    262         fprintf(stderr," or '%s'", value[n]);
    263     }
    264     fprintf(stderr,".\n\n");
    265     return -1;
    266 }
    267 
    268 static int cb_require(Action *a, int status, char *resp)
    269 {
    270     return cb_check(a, status, resp, 0);
    271 }
    272 
    273 static int cb_reject(Action *a, int status, char *resp)
    274 {
    275     return cb_check(a, status, resp, 1);
    276 }
    277 
    278 void fb_queue_require(const char *prod, const char *var,
    279 		int invert, unsigned nvalues, const char **value)
    280 {
    281     Action *a;
    282     a = queue_action(OP_QUERY, "getvar:%s", var);
    283     a->prod = prod;
    284     a->data = value;
    285     a->size = nvalues;
    286     a->msg = mkmsg("checking %s", var);
    287     a->func = invert ? cb_reject : cb_require;
    288     if (a->data == 0) die("out of memory");
    289 }
    290 
    291 static int cb_display(Action *a, int status, char *resp)
    292 {
    293     if (status) {
    294         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
    295         return status;
    296     }
    297     fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
    298     return 0;
    299 }
    300 
    301 void fb_queue_display(const char *var, const char *prettyname)
    302 {
    303     Action *a;
    304     a = queue_action(OP_QUERY, "getvar:%s", var);
    305     a->data = strdup(prettyname);
    306     if (a->data == 0) die("out of memory");
    307     a->func = cb_display;
    308 }
    309 
    310 static int cb_save(Action *a, int status, char *resp)
    311 {
    312     if (status) {
    313         fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
    314         return status;
    315     }
    316     strncpy(a->data, resp, a->size);
    317     return 0;
    318 }
    319 
    320 void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
    321 {
    322     Action *a;
    323     a = queue_action(OP_QUERY, "getvar:%s", var);
    324     a->data = (void *)dest;
    325     a->size = dest_size;
    326     a->func = cb_save;
    327 }
    328 
    329 static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused)
    330 {
    331     fprintf(stderr,"\n");
    332     return 0;
    333 }
    334 
    335 void fb_queue_reboot(void)
    336 {
    337     Action *a = queue_action(OP_COMMAND, "reboot");
    338     a->func = cb_do_nothing;
    339     a->msg = "rebooting";
    340 }
    341 
    342 void fb_queue_command(const char *cmd, const char *msg)
    343 {
    344     Action *a = queue_action(OP_COMMAND, cmd);
    345     a->msg = msg;
    346 }
    347 
    348 void fb_queue_download(const char *name, void *data, unsigned size)
    349 {
    350     Action *a = queue_action(OP_DOWNLOAD, "");
    351     a->data = data;
    352     a->size = size;
    353     a->msg = mkmsg("downloading '%s'", name);
    354 }
    355 
    356 void fb_queue_notice(const char *notice)
    357 {
    358     Action *a = queue_action(OP_NOTICE, "");
    359     a->data = (void*) notice;
    360 }
    361 
    362 void fb_queue_wait_for_disconnect(void)
    363 {
    364     queue_action(OP_WAIT_FOR_DISCONNECT, "");
    365 }
    366 
    367 int fb_execute_queue(usb_handle *usb)
    368 {
    369     Action *a;
    370     char resp[FB_RESPONSE_SZ+1];
    371     int status = 0;
    372 
    373     a = action_list;
    374     if (!a)
    375         return status;
    376     resp[FB_RESPONSE_SZ] = 0;
    377 
    378     double start = -1;
    379     for (a = action_list; a; a = a->next) {
    380         a->start = now();
    381         if (start < 0) start = a->start;
    382         if (a->msg) {
    383             // fprintf(stderr,"%30s... ",a->msg);
    384             fprintf(stderr,"%s...\n",a->msg);
    385         }
    386         if (a->op == OP_DOWNLOAD) {
    387             status = fb_download_data(usb, a->data, a->size);
    388             status = a->func(a, status, status ? fb_get_error() : "");
    389             if (status) break;
    390         } else if (a->op == OP_COMMAND) {
    391             status = fb_command(usb, a->cmd);
    392             status = a->func(a, status, status ? fb_get_error() : "");
    393             if (status) break;
    394         } else if (a->op == OP_QUERY) {
    395             status = fb_command_response(usb, a->cmd, resp);
    396             status = a->func(a, status, status ? fb_get_error() : 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(usb, a->data);
    402             status = a->func(a, status, status ? fb_get_error() : "");
    403             if (status) break;
    404         } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
    405             usb_wait_for_disconnect(usb);
    406         } else {
    407             die("bogus action");
    408         }
    409     }
    410 
    411     fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
    412     return status;
    413 }
    414 
    415 int fb_queue_is_empty(void)
    416 {
    417     return (action_list == NULL);
    418 }
    419