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 #include <fcntl.h> 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <unistd.h> 21 22 #include <ctype.h> 23 #include <errno.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include <cutils/properties.h> 29 30 #include "fs_mgr.h" 31 #include "fs_mgr_priv.h" 32 33 #include "bootloader.h" 34 35 // Copies slot_suffix from misc into |out_suffix|. Returns 0 on 36 // success, -1 on error or if there is no non-empty slot_suffix. 37 static int get_active_slot_suffix_from_misc(struct fstab *fstab, 38 char *out_suffix, 39 size_t suffix_len) 40 { 41 int n; 42 int misc_fd; 43 ssize_t num_read; 44 struct bootloader_message msg; 45 46 misc_fd = -1; 47 for (n = 0; n < fstab->num_entries; n++) { 48 if (strcmp(fstab->recs[n].mount_point, "/misc") == 0) { 49 misc_fd = open(fstab->recs[n].blk_device, O_RDONLY); 50 if (misc_fd == -1) { 51 ERROR("Error opening misc partition \"%s\" (%s)\n", 52 fstab->recs[n].blk_device, 53 strerror(errno)); 54 return -1; 55 } else { 56 break; 57 } 58 } 59 } 60 61 if (misc_fd == -1) { 62 ERROR("Error finding misc partition\n"); 63 return -1; 64 } 65 66 num_read = TEMP_FAILURE_RETRY(read(misc_fd, &msg, sizeof(msg))); 67 // Linux will never return partial reads when reading from block 68 // devices so no need to worry about them. 69 if (num_read != sizeof(msg)) { 70 ERROR("Error reading bootloader_message (%s)\n", strerror(errno)); 71 close(misc_fd); 72 return -1; 73 } 74 close(misc_fd); 75 if (msg.slot_suffix[0] == '\0') 76 return -1; 77 strncpy(out_suffix, msg.slot_suffix, suffix_len); 78 return 0; 79 } 80 81 // Gets slot_suffix from either the kernel cmdline / firmware or the 82 // misc partition. Sets |out_suffix| on success and returns 0. Returns 83 // -1 if slot_suffix could not be determined. 84 static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix, 85 size_t suffix_len) 86 { 87 char propbuf[PROPERTY_VALUE_MAX]; 88 89 // Get the suffix from the kernel commandline (note that we don't 90 // allow the empty suffix). On bootloaders natively supporting A/B 91 // we'll hit this path every time so don't bother logging it. 92 property_get("ro.boot.slot_suffix", propbuf, ""); 93 if (propbuf[0] != '\0') { 94 strncpy(out_suffix, propbuf, suffix_len); 95 return 0; 96 } 97 98 // If we couldn't get the suffix from the kernel cmdline, try the 99 // the misc partition. 100 if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) { 101 INFO("Using slot suffix \"%s\" from misc\n", out_suffix); 102 return 0; 103 } 104 105 ERROR("Error determining slot_suffix\n"); 106 107 return -1; 108 } 109 110 // Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error. 111 int fs_mgr_update_for_slotselect(struct fstab *fstab) 112 { 113 int n; 114 char suffix[PROPERTY_VALUE_MAX]; 115 int got_suffix = 0; 116 117 for (n = 0; n < fstab->num_entries; n++) { 118 if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) { 119 char *tmp; 120 121 if (!got_suffix) { 122 memset(suffix, '\0', sizeof(suffix)); 123 if (get_active_slot_suffix(fstab, suffix, 124 sizeof(suffix) - 1) != 0) { 125 return -1; 126 } 127 got_suffix = 1; 128 } 129 130 if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, 131 suffix) > 0) { 132 free(fstab->recs[n].blk_device); 133 fstab->recs[n].blk_device = tmp; 134 } else { 135 return -1; 136 } 137 } 138 } 139 return 0; 140 } 141