Home | History | Annotate | Download | only in boot_control_copy
      1 /*
      2  * Copyright (C) 2015 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 
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <linux/fs.h>
     21 #include <sys/ioctl.h>
     22 #include <sys/stat.h>
     23 #include <sys/types.h>
     24 #include <unistd.h>
     25 
     26 #include <arpa/inet.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 
     31 #include <cutils/properties.h>
     32 
     33 #include <bootloader.h>
     34 #include <fs_mgr.h>
     35 
     36 #include "bootinfo.h"
     37 
     38 // Open the appropriate fstab file and fallback to /fstab.device if
     39 // that's what's being used.
     40 static struct fstab *open_fstab(void)
     41 {
     42   char propbuf[PROPERTY_VALUE_MAX];
     43   char fstab_name[PROPERTY_VALUE_MAX + 32];
     44   struct fstab *fstab;
     45 
     46   property_get("ro.hardware", propbuf, "");
     47   snprintf(fstab_name, sizeof(fstab_name), "/fstab.%s", propbuf);
     48   fstab = fs_mgr_read_fstab(fstab_name);
     49   if (fstab != NULL)
     50     return fstab;
     51 
     52   fstab = fs_mgr_read_fstab("/fstab.device");
     53   return fstab;
     54 }
     55 
     56 int boot_info_open_partition(const char *name, uint64_t *out_size, int flags)
     57 {
     58   char *path;
     59   int fd;
     60   struct fstab *fstab;
     61   struct fstab_rec *record;
     62 
     63   // We can't use fs_mgr to look up |name| because fstab doesn't list
     64   // every slot partition (it uses the slotselect option to mask the
     65   // suffix) and |slot| is expected to be of that form, e.g. boot_a.
     66   //
     67   // We can however assume that there's an entry for the /misc mount
     68   // point and use that to get the device file for the misc
     69   // partition. From there we'll assume that a by-name scheme is used
     70   // so we can just replace the trailing "misc" by the given |name|,
     71   // e.g.
     72   //
     73   //   /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
     74   //   /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a
     75   //
     76   // If needed, it's possible to relax this assumption in the future
     77   // by trawling /sys/block looking for the appropriate sibling of
     78   // misc and then finding an entry in /dev matching the sysfs entry.
     79 
     80   fstab = open_fstab();
     81   if (fstab == NULL)
     82     return -1;
     83   record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
     84   if (record == NULL) {
     85     fs_mgr_free_fstab(fstab);
     86     return -1;
     87   }
     88   if (strcmp(name, "misc") == 0) {
     89     path = strdup(record->blk_device);
     90   } else {
     91     size_t trimmed_len, name_len;
     92     const char *end_slash = strrchr(record->blk_device, '/');
     93     if (end_slash == NULL) {
     94       fs_mgr_free_fstab(fstab);
     95       return -1;
     96     }
     97     trimmed_len = end_slash - record->blk_device + 1;
     98     name_len = strlen(name);
     99     path = calloc(trimmed_len + name_len + 1, 1);
    100     strncpy(path, record->blk_device, trimmed_len);
    101     strncpy(path + trimmed_len, name, name_len);
    102   }
    103   fs_mgr_free_fstab(fstab);
    104 
    105   fd = open(path, flags);
    106   free(path);
    107 
    108   // If we successfully opened the device, get size if requested.
    109   if (fd != -1 && out_size != NULL) {
    110     if (ioctl(fd, BLKGETSIZE64, out_size) != 0) {
    111       close(fd);
    112       return -1;
    113     }
    114   }
    115 
    116   return fd;
    117 }
    118 
    119 // As per struct bootloader_message which is defined in
    120 // bootable/recovery/bootloader.h we can use the 32 bytes in the
    121 // bootctrl_suffix field provided that they start with the active slot
    122 // suffix terminated by NUL. It just so happens that BrilloBootInfo is
    123 // laid out this way.
    124 #define BOOTINFO_OFFSET offsetof(struct bootloader_message, slot_suffix)
    125 
    126 bool boot_info_load(BrilloBootInfo *out_info)
    127 {
    128   int fd;
    129 
    130   memset(out_info, '\0', sizeof(BrilloBootInfo));
    131 
    132   fd = boot_info_open_partition("misc", NULL, O_RDONLY);
    133   if (fd == -1)
    134     return false;
    135   if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) {
    136     close(fd);
    137     return false;
    138   }
    139   ssize_t num_read;
    140   do {
    141     num_read = read(fd, (void*) out_info, sizeof(BrilloBootInfo));
    142   } while (num_read == -1 && errno == EINTR);
    143   close(fd);
    144   if (num_read != sizeof(BrilloBootInfo))
    145     return false;
    146   return true;
    147 }
    148 
    149 bool boot_info_save(BrilloBootInfo *info)
    150 {
    151   int fd;
    152 
    153   fd = boot_info_open_partition("misc", NULL, O_RDWR);
    154   if (fd == -1)
    155     return false;
    156   if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) {
    157     close(fd);
    158     return false;
    159   }
    160   ssize_t num_written;
    161   do {
    162     num_written = write(fd, (void*) info, sizeof(BrilloBootInfo));
    163   } while (num_written == -1 && errno == EINTR);
    164   close(fd);
    165   if (num_written != sizeof(BrilloBootInfo))
    166     return false;
    167   return true;
    168 }
    169 
    170 bool boot_info_validate(BrilloBootInfo* info)
    171 {
    172   if (info->magic[0] != 'B' ||
    173       info->magic[1] != 'C' ||
    174       info->magic[2] != 'c')
    175     return false;
    176   if (info->active_slot >= 2)
    177     return false;
    178   return true;
    179 }
    180 
    181 void boot_info_reset(BrilloBootInfo* info)
    182 {
    183   memset(info, '\0', sizeof(BrilloBootInfo));
    184   info->magic[0] = 'B';
    185   info->magic[1] = 'C';
    186   info->magic[2] = 'c';
    187 }
    188