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