boot_control_copy.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <sys/sysmacros.h>
  19. #include <unistd.h>
  20. #include <fcntl.h>
  21. #include <errno.h>
  22. #include <inttypes.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <fs_mgr.h>
  26. #include <hardware/hardware.h>
  27. #include <hardware/boot_control.h>
  28. #include "bootinfo.h"
  29. void module_init(boot_control_module_t *module)
  30. {
  31. }
  32. unsigned module_getNumberSlots(boot_control_module_t *module)
  33. {
  34. return 2;
  35. }
  36. static bool get_dev_t_for_partition(const char *name, dev_t *out_device)
  37. {
  38. int fd;
  39. struct stat statbuf;
  40. fd = boot_info_open_partition(name, NULL, O_RDONLY);
  41. if (fd == -1)
  42. return false;
  43. if (fstat(fd, &statbuf) != 0) {
  44. fprintf(stderr, "WARNING: Error getting information about part %s: %s\n",
  45. name, strerror(errno));
  46. close(fd);
  47. return false;
  48. }
  49. close(fd);
  50. *out_device = statbuf.st_rdev;
  51. return true;
  52. }
  53. unsigned module_getCurrentSlot(boot_control_module_t *module)
  54. {
  55. struct stat statbuf;
  56. dev_t system_a_dev, system_b_dev;
  57. if (stat("/system", &statbuf) != 0) {
  58. fprintf(stderr, "WARNING: Error getting information about /system: %s\n",
  59. strerror(errno));
  60. return 0;
  61. }
  62. if (!get_dev_t_for_partition("system_a", &system_a_dev) ||
  63. !get_dev_t_for_partition("system_b", &system_b_dev))
  64. return 0;
  65. if (statbuf.st_dev == system_a_dev) {
  66. return 0;
  67. } else if (statbuf.st_dev == system_b_dev) {
  68. return 1;
  69. } else {
  70. fprintf(stderr, "WARNING: Error determining current slot "
  71. "(/system dev_t of %d:%d does not match a=%d:%d or b=%d:%d)\n",
  72. major(statbuf.st_dev), minor(statbuf.st_dev),
  73. major(system_a_dev), minor(system_a_dev),
  74. major(system_b_dev), minor(system_b_dev));
  75. return 0;
  76. }
  77. }
  78. int module_markBootSuccessful(boot_control_module_t *module)
  79. {
  80. return 0;
  81. }
  82. #define COPY_BUF_SIZE (1024*1024)
  83. static bool copy_data(int src_fd, int dst_fd, size_t num_bytes)
  84. {
  85. char copy_buf[COPY_BUF_SIZE];
  86. size_t remaining;
  87. remaining = num_bytes;
  88. while (remaining > 0) {
  89. size_t num_to_read = remaining > COPY_BUF_SIZE ? COPY_BUF_SIZE : remaining;
  90. ssize_t num_read;
  91. do {
  92. num_read = read(src_fd, copy_buf, num_to_read);
  93. } while (num_read == -1 && errno == EINTR);
  94. if (num_read <= 0) {
  95. fprintf(stderr, "Error reading %zd bytes from source: %s\n",
  96. num_to_read, strerror(errno));
  97. return false;
  98. }
  99. size_t num_to_write = num_read;
  100. while (num_to_write > 0) {
  101. size_t offset = num_read - num_to_write;
  102. ssize_t num_written;
  103. do {
  104. num_written = write(dst_fd, copy_buf + offset, num_to_write);
  105. } while (num_written == -1 && errno == EINTR);
  106. if (num_written <= 0) {
  107. fprintf(stderr, "Error writing %zd bytes to destination: %s\n",
  108. num_to_write, strerror(errno));
  109. return false;
  110. }
  111. num_to_write -= num_written;
  112. }
  113. remaining -= num_read;
  114. }
  115. return true;
  116. }
  117. int module_setActiveBootSlot(boot_control_module_t *module, unsigned slot)
  118. {
  119. BrilloBootInfo info;
  120. int src_fd, dst_fd;
  121. uint64_t src_size, dst_size;
  122. char src_name[32];
  123. if (slot >= 2)
  124. return -EINVAL;
  125. if (!boot_info_load(&info)) {
  126. fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
  127. boot_info_reset(&info);
  128. } else {
  129. if (!boot_info_validate(&info)) {
  130. fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
  131. boot_info_reset(&info);
  132. }
  133. }
  134. info.active_slot = slot;
  135. info.slot_info[slot].bootable = true;
  136. snprintf(info.bootctrl_suffix,
  137. sizeof(info.bootctrl_suffix),
  138. "_%c", slot + 'a');
  139. if (!boot_info_save(&info)) {
  140. fprintf(stderr, "Error saving boot-info.\n");
  141. return -errno;
  142. }
  143. // Finally copy the contents of boot_X into boot.
  144. snprintf(src_name, sizeof(src_name), "boot_%c", slot + 'a');
  145. src_fd = boot_info_open_partition(src_name, &src_size, O_RDONLY);
  146. if (src_fd == -1) {
  147. fprintf(stderr, "Error opening \"%s\" partition.\n", src_name);
  148. return -errno;
  149. }
  150. dst_fd = boot_info_open_partition("boot", &dst_size, O_RDWR);
  151. if (dst_fd == -1) {
  152. fprintf(stderr, "Error opening \"boot\" partition.\n");
  153. close(src_fd);
  154. return -errno;
  155. }
  156. if (src_size != dst_size) {
  157. fprintf(stderr,
  158. "src (%" PRIu64 " bytes) and dst (%" PRIu64 " bytes) "
  159. "have different sizes.\n",
  160. src_size, dst_size);
  161. close(src_fd);
  162. close(dst_fd);
  163. return -EINVAL;
  164. }
  165. if (!copy_data(src_fd, dst_fd, src_size)) {
  166. close(src_fd);
  167. close(dst_fd);
  168. return -errno;
  169. }
  170. if (fsync(dst_fd) != 0) {
  171. fprintf(stderr, "Error calling fsync on destination: %s\n",
  172. strerror(errno));
  173. return -errno;
  174. }
  175. close(src_fd);
  176. close(dst_fd);
  177. return 0;
  178. }
  179. int module_setSlotAsUnbootable(struct boot_control_module *module, unsigned slot)
  180. {
  181. BrilloBootInfo info;
  182. if (slot >= 2)
  183. return -EINVAL;
  184. if (!boot_info_load(&info)) {
  185. fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
  186. boot_info_reset(&info);
  187. } else {
  188. if (!boot_info_validate(&info)) {
  189. fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
  190. boot_info_reset(&info);
  191. }
  192. }
  193. info.slot_info[slot].bootable = false;
  194. if (!boot_info_save(&info)) {
  195. fprintf(stderr, "Error saving boot-info.\n");
  196. return -errno;
  197. }
  198. return 0;
  199. }
  200. int module_isSlotBootable(struct boot_control_module *module, unsigned slot)
  201. {
  202. BrilloBootInfo info;
  203. if (slot >= 2)
  204. return -EINVAL;
  205. if (!boot_info_load(&info)) {
  206. fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
  207. boot_info_reset(&info);
  208. } else {
  209. if (!boot_info_validate(&info)) {
  210. fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
  211. boot_info_reset(&info);
  212. }
  213. }
  214. return info.slot_info[slot].bootable;
  215. }
  216. const char* module_getSuffix(boot_control_module_t *module, unsigned slot)
  217. {
  218. static const char* suffix[2] = {"_a", "_b"};
  219. if (slot >= 2)
  220. return NULL;
  221. return suffix[slot];
  222. }
  223. static struct hw_module_methods_t module_methods = {
  224. .open = NULL,
  225. };
  226. /* This boot_control HAL implementation emulates A/B by copying the
  227. * contents of the boot partition of the requested slot to the boot
  228. * partition. It hence works with bootloaders that are not yet aware
  229. * of A/B. This code is only intended to be used for development.
  230. */
  231. boot_control_module_t HAL_MODULE_INFO_SYM = {
  232. .common = {
  233. .tag = HARDWARE_MODULE_TAG,
  234. .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
  235. .hal_api_version = HARDWARE_HAL_API_VERSION,
  236. .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
  237. .name = "Copy Implementation of boot_control HAL",
  238. .author = "The Android Open Source Project",
  239. .methods = &module_methods,
  240. },
  241. .init = module_init,
  242. .getNumberSlots = module_getNumberSlots,
  243. .getCurrentSlot = module_getCurrentSlot,
  244. .markBootSuccessful = module_markBootSuccessful,
  245. .setActiveBootSlot = module_setActiveBootSlot,
  246. .setSlotAsUnbootable = module_setSlotAsUnbootable,
  247. .isSlotBootable = module_isSlotBootable,
  248. .getSuffix = module_getSuffix,
  249. };