OSDN Git Service

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