Home | History | Annotate | Download | only in recovery
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "bootloader.h"
     18 #include "common.h"
     19 #include "mtdutils/mtdutils.h"
     20 #include "roots.h"
     21 
     22 #include <errno.h>
     23 #include <stdio.h>
     24 #include <string.h>
     25 #include <sys/stat.h>
     26 #include <unistd.h>
     27 
     28 static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
     29 static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
     30 static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
     31 static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
     32 
     33 int get_bootloader_message(struct bootloader_message *out) {
     34     Volume* v = volume_for_path("/misc");
     35     if (v == NULL) {
     36       LOGE("Cannot load volume /misc!\n");
     37       return -1;
     38     }
     39     if (strcmp(v->fs_type, "mtd") == 0) {
     40         return get_bootloader_message_mtd(out, v);
     41     } else if (strcmp(v->fs_type, "emmc") == 0) {
     42         return get_bootloader_message_block(out, v);
     43     }
     44     LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
     45     return -1;
     46 }
     47 
     48 int set_bootloader_message(const struct bootloader_message *in) {
     49     Volume* v = volume_for_path("/misc");
     50     if (v == NULL) {
     51       LOGE("Cannot load volume /misc!\n");
     52       return -1;
     53     }
     54     if (strcmp(v->fs_type, "mtd") == 0) {
     55         return set_bootloader_message_mtd(in, v);
     56     } else if (strcmp(v->fs_type, "emmc") == 0) {
     57         return set_bootloader_message_block(in, v);
     58     }
     59     LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
     60     return -1;
     61 }
     62 
     63 // ------------------------------
     64 // for misc partitions on MTD
     65 // ------------------------------
     66 
     67 static const int MISC_PAGES = 3;         // number of pages to save
     68 static const int MISC_COMMAND_PAGE = 1;  // bootloader command is this page
     69 
     70 static int get_bootloader_message_mtd(struct bootloader_message *out,
     71                                       const Volume* v) {
     72     size_t write_size;
     73     mtd_scan_partitions();
     74     const MtdPartition *part = mtd_find_partition_by_name(v->device);
     75     if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
     76         LOGE("Can't find %s\n", v->device);
     77         return -1;
     78     }
     79 
     80     MtdReadContext *read = mtd_read_partition(part);
     81     if (read == NULL) {
     82         LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
     83         return -1;
     84     }
     85 
     86     const ssize_t size = write_size * MISC_PAGES;
     87     char data[size];
     88     ssize_t r = mtd_read_data(read, data, size);
     89     if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
     90     mtd_read_close(read);
     91     if (r != size) return -1;
     92 
     93     memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
     94     return 0;
     95 }
     96 static int set_bootloader_message_mtd(const struct bootloader_message *in,
     97                                       const Volume* v) {
     98     size_t write_size;
     99     mtd_scan_partitions();
    100     const MtdPartition *part = mtd_find_partition_by_name(v->device);
    101     if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
    102         LOGE("Can't find %s\n", v->device);
    103         return -1;
    104     }
    105 
    106     MtdReadContext *read = mtd_read_partition(part);
    107     if (read == NULL) {
    108         LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
    109         return -1;
    110     }
    111 
    112     ssize_t size = write_size * MISC_PAGES;
    113     char data[size];
    114     ssize_t r = mtd_read_data(read, data, size);
    115     if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
    116     mtd_read_close(read);
    117     if (r != size) return -1;
    118 
    119     memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
    120 
    121     MtdWriteContext *write = mtd_write_partition(part);
    122     if (write == NULL) {
    123         LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
    124         return -1;
    125     }
    126     if (mtd_write_data(write, data, size) != size) {
    127         LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno));
    128         mtd_write_close(write);
    129         return -1;
    130     }
    131     if (mtd_write_close(write)) {
    132         LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno));
    133         return -1;
    134     }
    135 
    136     LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
    137     return 0;
    138 }
    139 
    140 
    141 // ------------------------------------
    142 // for misc partitions on block devices
    143 // ------------------------------------
    144 
    145 static void wait_for_device(const char* fn) {
    146     int tries = 0;
    147     int ret;
    148     struct stat buf;
    149     do {
    150         ++tries;
    151         ret = stat(fn, &buf);
    152         if (ret) {
    153             printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
    154             sleep(1);
    155         }
    156     } while (ret && tries < 10);
    157     if (ret) {
    158         printf("failed to stat %s\n", fn);
    159     }
    160 }
    161 
    162 static int get_bootloader_message_block(struct bootloader_message *out,
    163                                         const Volume* v) {
    164     wait_for_device(v->device);
    165     FILE* f = fopen(v->device, "rb");
    166     if (f == NULL) {
    167         LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
    168         return -1;
    169     }
    170     struct bootloader_message temp;
    171     int count = fread(&temp, sizeof(temp), 1, f);
    172     if (count != 1) {
    173         LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno));
    174         return -1;
    175     }
    176     if (fclose(f) != 0) {
    177         LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
    178         return -1;
    179     }
    180     memcpy(out, &temp, sizeof(temp));
    181     return 0;
    182 }
    183 
    184 static int set_bootloader_message_block(const struct bootloader_message *in,
    185                                         const Volume* v) {
    186     wait_for_device(v->device);
    187     FILE* f = fopen(v->device, "wb");
    188     if (f == NULL) {
    189         LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
    190         return -1;
    191     }
    192     int count = fwrite(in, sizeof(*in), 1, f);
    193     if (count != 1) {
    194         LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno));
    195         return -1;
    196     }
    197     if (fclose(f) != 0) {
    198         LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
    199         return -1;
    200     }
    201     return 0;
    202 }
    203