blob: a799eb4e38c3b44d22a8b2f7dfc276efed30f7e2 [file] [log] [blame]
micky387e96abca2019-06-11 02:35:20 +02001/*
2 * Copyright (c) 2013,2016, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define _LARGEFILE64_SOURCE /* enable lseek64() */
31
32/******************************************************************************
33 * INCLUDE SECTION
34 ******************************************************************************/
35#include <stdio.h>
36#include <fcntl.h>
37#include <string.h>
38#include <errno.h>
micky387e96abca2019-06-11 02:35:20 +020039#include <sys/stat.h>
40#include <sys/ioctl.h>
LuK133788dd8102020-04-06 12:45:17 +020041#ifndef _GENERIC_KERNEL_HEADERS
micky387e96abca2019-06-11 02:35:20 +020042#include <scsi/ufs/ioctl.h>
43#include <scsi/ufs/ufs.h>
LuK133788dd8102020-04-06 12:45:17 +020044#endif
micky387e96abca2019-06-11 02:35:20 +020045#include <unistd.h>
46#include <linux/fs.h>
47#include <limits.h>
48#include <dirent.h>
49#include <linux/kernel.h>
micky387e96abca2019-06-11 02:35:20 +020050#include <map>
51#include <vector>
52#include <string>
LuK133788dd8102020-04-06 12:45:17 +020053#ifndef __STDC_FORMAT_MACROS
54#define __STDC_FORMAT_MACROS
55#endif
56#include <inttypes.h>
57
58
micky387e96abca2019-06-11 02:35:20 +020059#define LOG_TAG "gpt-utils"
60#include <log/log.h>
61#include <cutils/properties.h>
62#include "gpt-utils.h"
Logan Chienc4ab4942017-05-17 15:36:58 +080063#include <zlib.h>
LuK133788dd8102020-04-06 12:45:17 +020064#include <endian.h>
micky387e96abca2019-06-11 02:35:20 +020065
66
67/******************************************************************************
68 * DEFINE SECTION
69 ******************************************************************************/
70#define BLK_DEV_FILE "/dev/block/mmcblk0"
71/* list the names of the backed-up partitions to be swapped */
72/* extension used for the backup partitions - tzbak, abootbak, etc. */
73#define BAK_PTN_NAME_EXT "bak"
74#define XBL_PRIMARY "/dev/block/bootdevice/by-name/xbl"
75#define XBL_BACKUP "/dev/block/bootdevice/by-name/xblbak"
76#define XBL_AB_PRIMARY "/dev/block/bootdevice/by-name/xbl_a"
77#define XBL_AB_SECONDARY "/dev/block/bootdevice/by-name/xbl_b"
78/* GPT defines */
79#define MAX_LUNS 26
80//Size of the buffer that needs to be passed to the UFS ioctl
81#define UFS_ATTR_DATA_SIZE 32
82//This will allow us to get the root lun path from the path to the partition.
83//i.e: from /dev/block/sdaXXX get /dev/block/sda. The assumption here is that
84//the boot critical luns lie between sda to sdz which is acceptable because
85//only user added external disks,etc would lie beyond that limit which do not
86//contain partitions that interest us here.
87#define PATH_TRUNCATE_LOC (sizeof("/dev/block/sda") - 1)
88
89//From /dev/block/sda get just sda
90#define LUN_NAME_START_LOC (sizeof("/dev/block/") - 1)
91#define BOOT_LUN_A_ID 1
92#define BOOT_LUN_B_ID 2
93/******************************************************************************
94 * MACROS
95 ******************************************************************************/
96
97
98#define GET_4_BYTES(ptr) ((uint32_t) *((uint8_t *)(ptr)) | \
99 ((uint32_t) *((uint8_t *)(ptr) + 1) << 8) | \
100 ((uint32_t) *((uint8_t *)(ptr) + 2) << 16) | \
101 ((uint32_t) *((uint8_t *)(ptr) + 3) << 24))
102
103#define GET_8_BYTES(ptr) ((uint64_t) *((uint8_t *)(ptr)) | \
104 ((uint64_t) *((uint8_t *)(ptr) + 1) << 8) | \
105 ((uint64_t) *((uint8_t *)(ptr) + 2) << 16) | \
106 ((uint64_t) *((uint8_t *)(ptr) + 3) << 24) | \
107 ((uint64_t) *((uint8_t *)(ptr) + 4) << 32) | \
108 ((uint64_t) *((uint8_t *)(ptr) + 5) << 40) | \
109 ((uint64_t) *((uint8_t *)(ptr) + 6) << 48) | \
110 ((uint64_t) *((uint8_t *)(ptr) + 7) << 56))
111
112#define PUT_4_BYTES(ptr, y) *((uint8_t *)(ptr)) = (y) & 0xff; \
113 *((uint8_t *)(ptr) + 1) = ((y) >> 8) & 0xff; \
114 *((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
115 *((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
116
117/******************************************************************************
118 * TYPES
119 ******************************************************************************/
120using namespace std;
121enum gpt_state {
122 GPT_OK = 0,
123 GPT_BAD_SIGNATURE,
124 GPT_BAD_CRC
125};
126//List of LUN's containing boot critical images.
127//Required in the case of UFS devices
128struct update_data {
129 char lun_list[MAX_LUNS][PATH_MAX];
130 uint32_t num_valid_entries;
131};
132
133/******************************************************************************
134 * FUNCTIONS
135 ******************************************************************************/
136/**
137 * ==========================================================================
138 *
139 * \brief Read/Write len bytes from/to block dev
140 *
141 * \param [in] fd block dev file descriptor (returned from open)
142 * \param [in] rw RW flag: 0 - read, != 0 - write
143 * \param [in] offset block dev offset [bytes] - RW start position
144 * \param [in] buf Pointer to the buffer containing the data
145 * \param [in] len RW size in bytes. Buf must be at least that big
146 *
147 * \return 0 on success
148 *
149 * ==========================================================================
150 */
151static int blk_rw(int fd, int rw, int64_t offset, uint8_t *buf, unsigned len)
152{
153 int r;
154
155 if (lseek64(fd, offset, SEEK_SET) < 0) {
LuK133788dd8102020-04-06 12:45:17 +0200156 fprintf(stderr, "block dev lseek64 %" PRIi64 " failed: %s\n", offset,
micky387e96abca2019-06-11 02:35:20 +0200157 strerror(errno));
158 return -1;
159 }
160
161 if (rw)
162 r = write(fd, buf, len);
163 else
164 r = read(fd, buf, len);
165
166 if (r < 0)
167 fprintf(stderr, "block dev %s failed: %s\n", rw ? "write" : "read",
168 strerror(errno));
169 else
170 r = 0;
171
172 return r;
173}
174
175
176
177/**
178 * ==========================================================================
179 *
180 * \brief Search within GPT for partition entry with the given name
181 * or it's backup twin (name-bak).
182 *
183 * \param [in] ptn_name Partition name to seek
184 * \param [in] pentries_start Partition entries array start pointer
185 * \param [in] pentries_end Partition entries array end pointer
186 * \param [in] pentry_size Single partition entry size [bytes]
187 *
188 * \return First partition entry pointer that matches the name or NULL
189 *
190 * ==========================================================================
191 */
192static uint8_t *gpt_pentry_seek(const char *ptn_name,
193 const uint8_t *pentries_start,
194 const uint8_t *pentries_end,
195 uint32_t pentry_size)
196{
LuK133788dd8102020-04-06 12:45:17 +0200197 char *pentry_name;
198 unsigned len = strlen(ptn_name);
199 unsigned i;
200 char name8[MAX_GPT_NAME_SIZE] = {0}; // initialize with null
micky387e96abca2019-06-11 02:35:20 +0200201
202 for (pentry_name = (char *) (pentries_start + PARTITION_NAME_OFFSET);
LuK133788dd8102020-04-06 12:45:17 +0200203 pentry_name < (char *) pentries_end;
204 pentry_name += pentry_size) {
micky387e96abca2019-06-11 02:35:20 +0200205
206 /* Partition names in GPT are UTF-16 - ignoring UTF-16 2nd byte */
207 for (i = 0; i < sizeof(name8) / 2; i++)
208 name8[i] = pentry_name[i * 2];
LuK133788dd8102020-04-06 12:45:17 +0200209 name8[i] = '\0';
210
211 if (!strncmp(ptn_name, name8, len)) {
micky387e96abca2019-06-11 02:35:20 +0200212 if (name8[len] == 0 || !strcmp(&name8[len], BAK_PTN_NAME_EXT))
213 return (uint8_t *) (pentry_name - PARTITION_NAME_OFFSET);
LuK133788dd8102020-04-06 12:45:17 +0200214 }
micky387e96abca2019-06-11 02:35:20 +0200215 }
216
217 return NULL;
218}
219
220
221
222/**
223 * ==========================================================================
224 *
225 * \brief Swaps boot chain in GPT partition entries array
226 *
227 * \param [in] pentries_start Partition entries array start
228 * \param [in] pentries_end Partition entries array end
229 * \param [in] pentry_size Single partition entry size
230 *
231 * \return 0 on success, 1 if no backup partitions found
232 *
233 * ==========================================================================
234 */
235static int gpt_boot_chain_swap(const uint8_t *pentries_start,
236 const uint8_t *pentries_end,
237 uint32_t pentry_size)
238{
239 const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
240
241 int backup_not_found = 1;
242 unsigned i;
243
244 for (i = 0; i < ARRAY_SIZE(ptn_swap_list); i++) {
245 uint8_t *ptn_entry;
246 uint8_t *ptn_bak_entry;
247 uint8_t ptn_swap[PTN_ENTRY_SIZE];
248 //Skip the xbl partition on UFS devices. That is handled
249 //seperately.
250 if (gpt_utils_is_ufs_device() && !strncmp(ptn_swap_list[i],
251 PTN_XBL,
252 strlen(PTN_XBL)))
253 continue;
254
255 ptn_entry = gpt_pentry_seek(ptn_swap_list[i], pentries_start,
256 pentries_end, pentry_size);
257 if (ptn_entry == NULL)
258 continue;
259
260 ptn_bak_entry = gpt_pentry_seek(ptn_swap_list[i],
261 ptn_entry + pentry_size, pentries_end, pentry_size);
262 if (ptn_bak_entry == NULL) {
263 fprintf(stderr, "'%s' partition not backup - skip safe update\n",
264 ptn_swap_list[i]);
265 continue;
266 }
267
268 /* swap primary <-> backup partition entries */
269 memcpy(ptn_swap, ptn_entry, PTN_ENTRY_SIZE);
270 memcpy(ptn_entry, ptn_bak_entry, PTN_ENTRY_SIZE);
271 memcpy(ptn_bak_entry, ptn_swap, PTN_ENTRY_SIZE);
272 backup_not_found = 0;
273 }
274
275 return backup_not_found;
276}
277
278
279
280/**
281 * ==========================================================================
282 *
283 * \brief Sets secondary GPT boot chain
284 *
285 * \param [in] fd block dev file descriptor
286 * \param [in] boot Boot chain to switch to
287 *
288 * \return 0 on success
289 *
290 * ==========================================================================
291 */
292static int gpt2_set_boot_chain(int fd, enum boot_chain boot)
293{
294 int64_t gpt2_header_offset;
295 uint64_t pentries_start_offset;
296 uint32_t gpt_header_size;
297 uint32_t pentry_size;
298 uint32_t pentries_array_size;
299
300 uint8_t *gpt_header = NULL;
301 uint8_t *pentries = NULL;
302 uint32_t crc;
LuK133788dd8102020-04-06 12:45:17 +0200303 uint32_t crc_zero;
micky387e96abca2019-06-11 02:35:20 +0200304 uint32_t blk_size = 0;
305 int r;
306
LuK133788dd8102020-04-06 12:45:17 +0200307
308 crc_zero = crc32(0L, Z_NULL, 0);
micky387e96abca2019-06-11 02:35:20 +0200309 if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
310 fprintf(stderr, "Failed to get GPT device block size: %s\n",
311 strerror(errno));
312 r = -1;
313 goto EXIT;
314 }
315 gpt_header = (uint8_t*)malloc(blk_size);
316 if (!gpt_header) {
317 fprintf(stderr, "Failed to allocate memory to hold GPT block\n");
318 r = -1;
319 goto EXIT;
320 }
321 gpt2_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
322 if (gpt2_header_offset < 0) {
323 fprintf(stderr, "Getting secondary GPT header offset failed: %s\n",
324 strerror(errno));
325 r = -1;
326 goto EXIT;
327 }
328
329 /* Read primary GPT header from block dev */
330 r = blk_rw(fd, 0, blk_size, gpt_header, blk_size);
331
332 if (r) {
333 fprintf(stderr, "Failed to read primary GPT header from blk dev\n");
334 goto EXIT;
335 }
336 pentries_start_offset =
337 GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * blk_size;
338 pentry_size = GET_4_BYTES(gpt_header + PENTRY_SIZE_OFFSET);
339 pentries_array_size =
340 GET_4_BYTES(gpt_header + PARTITION_COUNT_OFFSET) * pentry_size;
341
342 pentries = (uint8_t *) calloc(1, pentries_array_size);
343 if (pentries == NULL) {
344 fprintf(stderr,
345 "Failed to alloc memory for GPT partition entries array\n");
346 r = -1;
347 goto EXIT;
348 }
349 /* Read primary GPT partititon entries array from block dev */
350 r = blk_rw(fd, 0, pentries_start_offset, pentries, pentries_array_size);
351 if (r)
352 goto EXIT;
353
LuK133788dd8102020-04-06 12:45:17 +0200354 crc = crc32(crc_zero, pentries, pentries_array_size);
micky387e96abca2019-06-11 02:35:20 +0200355 if (GET_4_BYTES(gpt_header + PARTITION_CRC_OFFSET) != crc) {
356 fprintf(stderr, "Primary GPT partition entries array CRC invalid\n");
357 r = -1;
358 goto EXIT;
359 }
360
361 /* Read secondary GPT header from block dev */
362 r = blk_rw(fd, 0, gpt2_header_offset, gpt_header, blk_size);
363 if (r)
364 goto EXIT;
365
366 gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
367 pentries_start_offset =
368 GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * blk_size;
369
370 if (boot == BACKUP_BOOT) {
371 r = gpt_boot_chain_swap(pentries, pentries + pentries_array_size,
372 pentry_size);
373 if (r)
374 goto EXIT;
375 }
376
LuK133788dd8102020-04-06 12:45:17 +0200377 crc = crc32(crc_zero, pentries, pentries_array_size);
micky387e96abca2019-06-11 02:35:20 +0200378 PUT_4_BYTES(gpt_header + PARTITION_CRC_OFFSET, crc);
379
380 /* header CRC is calculated with this field cleared */
381 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
LuK133788dd8102020-04-06 12:45:17 +0200382 crc = crc32(crc_zero, gpt_header, gpt_header_size);
micky387e96abca2019-06-11 02:35:20 +0200383 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
384
385 /* Write the modified GPT header back to block dev */
386 r = blk_rw(fd, 1, gpt2_header_offset, gpt_header, blk_size);
387 if (!r)
388 /* Write the modified GPT partititon entries array back to block dev */
389 r = blk_rw(fd, 1, pentries_start_offset, pentries,
390 pentries_array_size);
391
392EXIT:
393 if(gpt_header)
394 free(gpt_header);
395 if (pentries)
396 free(pentries);
397 return r;
398}
399
400/**
401 * ==========================================================================
402 *
403 * \brief Checks GPT state (header signature and CRC)
404 *
405 * \param [in] fd block dev file descriptor
406 * \param [in] gpt GPT header to be checked
407 * \param [out] state GPT header state
408 *
409 * \return 0 on success
410 *
411 * ==========================================================================
412 */
413static int gpt_get_state(int fd, enum gpt_instance gpt, enum gpt_state *state)
414{
415 int64_t gpt_header_offset;
416 uint32_t gpt_header_size;
417 uint8_t *gpt_header = NULL;
418 uint32_t crc;
LuK133788dd8102020-04-06 12:45:17 +0200419 uint32_t crc_zero;
micky387e96abca2019-06-11 02:35:20 +0200420 uint32_t blk_size = 0;
421
422 *state = GPT_OK;
423
LuK133788dd8102020-04-06 12:45:17 +0200424 crc_zero = crc32(0L, Z_NULL, 0);
micky387e96abca2019-06-11 02:35:20 +0200425 if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
426 fprintf(stderr, "Failed to get GPT device block size: %s\n",
427 strerror(errno));
428 goto error;
429 }
430 gpt_header = (uint8_t*)malloc(blk_size);
431 if (!gpt_header) {
432 fprintf(stderr, "gpt_get_state:Failed to alloc memory for header\n");
433 goto error;
434 }
435 if (gpt == PRIMARY_GPT)
436 gpt_header_offset = blk_size;
437 else {
438 gpt_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
439 if (gpt_header_offset < 0) {
440 fprintf(stderr, "gpt_get_state:Seek to end of GPT part fail\n");
441 goto error;
442 }
443 }
444
445 if (blk_rw(fd, 0, gpt_header_offset, gpt_header, blk_size)) {
446 fprintf(stderr, "gpt_get_state: blk_rw failed\n");
447 goto error;
448 }
449 if (memcmp(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE)))
450 *state = GPT_BAD_SIGNATURE;
451 gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
452
453 crc = GET_4_BYTES(gpt_header + HEADER_CRC_OFFSET);
454 /* header CRC is calculated with this field cleared */
455 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
LuK133788dd8102020-04-06 12:45:17 +0200456 if (crc32(crc_zero, gpt_header, gpt_header_size) != crc)
micky387e96abca2019-06-11 02:35:20 +0200457 *state = GPT_BAD_CRC;
458 free(gpt_header);
459 return 0;
460error:
461 if (gpt_header)
462 free(gpt_header);
463 return -1;
464}
465
466
467
468/**
469 * ==========================================================================
470 *
471 * \brief Sets GPT header state (used to corrupt and fix GPT signature)
472 *
473 * \param [in] fd block dev file descriptor
474 * \param [in] gpt GPT header to be checked
475 * \param [in] state GPT header state to set (GPT_OK or GPT_BAD_SIGNATURE)
476 *
477 * \return 0 on success
478 *
479 * ==========================================================================
480 */
481static int gpt_set_state(int fd, enum gpt_instance gpt, enum gpt_state state)
482{
483 int64_t gpt_header_offset;
484 uint32_t gpt_header_size;
485 uint8_t *gpt_header = NULL;
486 uint32_t crc;
LuK133788dd8102020-04-06 12:45:17 +0200487 uint32_t crc_zero;
micky387e96abca2019-06-11 02:35:20 +0200488 uint32_t blk_size = 0;
489
LuK133788dd8102020-04-06 12:45:17 +0200490 crc_zero = crc32(0L, Z_NULL, 0);
micky387e96abca2019-06-11 02:35:20 +0200491 if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
492 fprintf(stderr, "Failed to get GPT device block size: %s\n",
493 strerror(errno));
494 goto error;
495 }
496 gpt_header = (uint8_t*)malloc(blk_size);
497 if (!gpt_header) {
498 fprintf(stderr, "Failed to alloc memory for gpt header\n");
499 goto error;
500 }
501 if (gpt == PRIMARY_GPT)
502 gpt_header_offset = blk_size;
503 else {
504 gpt_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
505 if (gpt_header_offset < 0) {
506 fprintf(stderr, "Failed to seek to end of GPT device\n");
507 goto error;
508 }
509 }
510 if (blk_rw(fd, 0, gpt_header_offset, gpt_header, blk_size)) {
511 fprintf(stderr, "Failed to r/w gpt header\n");
512 goto error;
513 }
514 if (state == GPT_OK)
515 memcpy(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE));
516 else if (state == GPT_BAD_SIGNATURE)
517 *gpt_header = 0;
518 else {
519 fprintf(stderr, "gpt_set_state: Invalid state\n");
520 goto error;
521 }
522
523 gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
524
525 /* header CRC is calculated with this field cleared */
526 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
LuK133788dd8102020-04-06 12:45:17 +0200527 crc = crc32(crc_zero, gpt_header, gpt_header_size);
micky387e96abca2019-06-11 02:35:20 +0200528 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
529
530 if (blk_rw(fd, 1, gpt_header_offset, gpt_header, blk_size)) {
531 fprintf(stderr, "gpt_set_state: blk write failed\n");
532 goto error;
533 }
534 return 0;
535error:
536 if(gpt_header)
537 free(gpt_header);
538 return -1;
539}
540
541int get_scsi_node_from_bootdevice(const char *bootdev_path,
542 char *sg_node_path,
543 size_t buf_size)
544{
545 char sg_dir_path[PATH_MAX] = {0};
546 char real_path[PATH_MAX] = {0};
547 DIR *scsi_dir = NULL;
548 struct dirent *de;
549 int node_found = 0;
550 if (!bootdev_path || !sg_node_path) {
551 fprintf(stderr, "%s : invalid argument\n",
552 __func__);
553 goto error;
554 }
555 if (readlink(bootdev_path, real_path, sizeof(real_path) - 1) < 0) {
556 fprintf(stderr, "failed to resolve link for %s(%s)\n",
557 bootdev_path,
558 strerror(errno));
559 goto error;
560 }
561 if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
562 fprintf(stderr, "Unrecognized path :%s:\n",
563 real_path);
564 goto error;
565 }
566 //For the safe side in case there are additional partitions on
567 //the XBL lun we truncate the name.
568 real_path[PATH_TRUNCATE_LOC] = '\0';
569 if(strlen(real_path) < LUN_NAME_START_LOC + 1){
570 fprintf(stderr, "Unrecognized truncated path :%s:\n",
571 real_path);
572 goto error;
573 }
574 //This will give us /dev/block/sdb/device/scsi_generic
575 //which contains a file sgY whose name gives us the path
576 //to /dev/sgY which we return
577 snprintf(sg_dir_path, sizeof(sg_dir_path) - 1,
578 "/sys/block/%s/device/scsi_generic",
579 &real_path[LUN_NAME_START_LOC]);
580 scsi_dir = opendir(sg_dir_path);
581 if (!scsi_dir) {
582 fprintf(stderr, "%s : Failed to open %s(%s)\n",
583 __func__,
584 sg_dir_path,
585 strerror(errno));
586 goto error;
587 }
588 while((de = readdir(scsi_dir))) {
589 if (de->d_name[0] == '.')
590 continue;
591 else if (!strncmp(de->d_name, "sg", 2)) {
592 snprintf(sg_node_path,
593 buf_size -1,
594 "/dev/%s",
595 de->d_name);
596 fprintf(stderr, "%s:scsi generic node is :%s:\n",
597 __func__,
598 sg_node_path);
599 node_found = 1;
600 break;
601 }
602 }
603 if(!node_found) {
604 fprintf(stderr,"%s: Unable to locate scsi generic node\n",
605 __func__);
606 goto error;
607 }
608 closedir(scsi_dir);
609 return 0;
610error:
611 if (scsi_dir)
612 closedir(scsi_dir);
613 return -1;
614}
615
616int set_boot_lun(char *sg_dev, uint8_t boot_lun_id)
617{
LuK133788dd8102020-04-06 12:45:17 +0200618#ifndef _GENERIC_KERNEL_HEADERS
micky387e96abca2019-06-11 02:35:20 +0200619 int fd = -1;
620 int rc;
621 struct ufs_ioctl_query_data *data = NULL;
622 size_t ioctl_data_size = sizeof(struct ufs_ioctl_query_data) + UFS_ATTR_DATA_SIZE;
623
624 data = (struct ufs_ioctl_query_data*)malloc(ioctl_data_size);
625 if (!data) {
626 fprintf(stderr, "%s: Failed to alloc query data struct\n",
627 __func__);
628 goto error;
629 }
630 memset(data, 0, ioctl_data_size);
631 data->opcode = UPIU_QUERY_OPCODE_WRITE_ATTR;
632 data->idn = QUERY_ATTR_IDN_BOOT_LU_EN;
633 data->buf_size = UFS_ATTR_DATA_SIZE;
634 data->buffer[0] = boot_lun_id;
635 fd = open(sg_dev, O_RDWR);
636 if (fd < 0) {
637 fprintf(stderr, "%s: Failed to open %s(%s)\n",
638 __func__,
639 sg_dev,
640 strerror(errno));
641 goto error;
642 }
643 rc = ioctl(fd, UFS_IOCTL_QUERY, data);
644 if (rc) {
645 fprintf(stderr, "%s: UFS query ioctl failed(%s)\n",
646 __func__,
647 strerror(errno));
648 goto error;
649 }
650 close(fd);
651 free(data);
652 return 0;
653error:
654 if (fd >= 0)
655 close(fd);
656 if (data)
657 free(data);
658 return -1;
LuK133788dd8102020-04-06 12:45:17 +0200659#else
660 return 0;
661#endif
micky387e96abca2019-06-11 02:35:20 +0200662}
663
664//Swtich betwieen using either the primary or the backup
665//boot LUN for boot. This is required since UFS boot partitions
666//cannot have a backup GPT which is what we use for failsafe
667//updates of the other 'critical' partitions. This function will
668//not be invoked for emmc targets and on UFS targets is only required
669//to be invoked for XBL.
670//
671//The algorithm to do this is as follows:
672//- Find the real block device(eg: /dev/block/sdb) that corresponds
673// to the /dev/block/bootdevice/by-name/xbl(bak) symlink
674//
675//- Once we have the block device 'node' name(sdb in the above example)
676// use this node to to locate the scsi generic device that represents
677// it by checking the file /sys/block/sdb/device/scsi_generic/sgY
678//
679//- Once we locate sgY we call the query ioctl on /dev/sgy to switch
680//the boot lun to either LUNA or LUNB
681int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
682{
683 struct stat st;
684 ///sys/block/sdX/device/scsi_generic/
685 char sg_dev_node[PATH_MAX] = {0};
686 uint8_t boot_lun_id = 0;
687 const char *boot_dev = NULL;
688
689 if (chain == BACKUP_BOOT) {
690 boot_lun_id = BOOT_LUN_B_ID;
691 if (!stat(XBL_BACKUP, &st))
692 boot_dev = XBL_BACKUP;
693 else if (!stat(XBL_AB_SECONDARY, &st))
694 boot_dev = XBL_AB_SECONDARY;
695 else {
696 fprintf(stderr, "%s: Failed to locate secondary xbl\n",
697 __func__);
698 goto error;
699 }
700 } else if (chain == NORMAL_BOOT) {
701 boot_lun_id = BOOT_LUN_A_ID;
702 if (!stat(XBL_PRIMARY, &st))
703 boot_dev = XBL_PRIMARY;
704 else if (!stat(XBL_AB_PRIMARY, &st))
705 boot_dev = XBL_AB_PRIMARY;
706 else {
707 fprintf(stderr, "%s: Failed to locate primary xbl\n",
708 __func__);
709 goto error;
710 }
711 } else {
712 fprintf(stderr, "%s: Invalid boot chain id\n", __func__);
713 goto error;
714 }
715 //We need either both xbl and xblbak or both xbl_a and xbl_b to exist at
716 //the same time. If not the current configuration is invalid.
717 if((stat(XBL_PRIMARY, &st) ||
718 stat(XBL_BACKUP, &st)) &&
719 (stat(XBL_AB_PRIMARY, &st) ||
720 stat(XBL_AB_SECONDARY, &st))) {
721 fprintf(stderr, "%s:primary/secondary XBL prt not found(%s)\n",
722 __func__,
723 strerror(errno));
724 goto error;
725 }
726 fprintf(stderr, "%s: setting %s lun as boot lun\n",
727 __func__,
728 boot_dev);
729 if (get_scsi_node_from_bootdevice(boot_dev,
730 sg_dev_node,
731 sizeof(sg_dev_node))) {
732 fprintf(stderr, "%s: Failed to get scsi node path for xblbak\n",
733 __func__);
734 goto error;
735 }
736 if (set_boot_lun(sg_dev_node, boot_lun_id)) {
737 fprintf(stderr, "%s: Failed to set xblbak as boot partition\n",
738 __func__);
739 goto error;
740 }
741 return 0;
742error:
743 return -1;
744}
745
746int gpt_utils_is_ufs_device()
747{
748 char bootdevice[PROPERTY_VALUE_MAX] = {0};
749 property_get("ro.boot.bootdevice", bootdevice, "N/A");
750 if (strlen(bootdevice) < strlen(".ufshc") + 1)
751 return 0;
752 return (!strncmp(&bootdevice[strlen(bootdevice) - strlen(".ufshc")],
753 ".ufshc",
754 sizeof(".ufshc")));
755}
756//dev_path is the path to the block device that contains the GPT image that
757//needs to be updated. This would be the device which holds one or more critical
758//boot partitions and their backups. In the case of EMMC this function would
759//be invoked only once on /dev/block/mmcblk1 since it holds the GPT image
760//containing all the partitions For UFS devices it could potentially be
761//invoked multiple times, once for each LUN containing critical image(s) and
762//their backups
763int prepare_partitions(enum boot_update_stage stage, const char *dev_path)
764{
765 int r = 0;
766 int fd = -1;
767 int is_ufs = gpt_utils_is_ufs_device();
768 enum gpt_state gpt_prim, gpt_second;
769 enum boot_update_stage internal_stage;
770 struct stat xbl_partition_stat;
micky387e96abca2019-06-11 02:35:20 +0200771
772 if (!dev_path) {
773 fprintf(stderr, "%s: Invalid dev_path\n",
774 __func__);
775 r = -1;
776 goto EXIT;
777 }
778 fd = open(dev_path, O_RDWR);
779 if (fd < 0) {
780 fprintf(stderr, "%s: Opening '%s' failed: %s\n",
781 __func__,
782 BLK_DEV_FILE,
783 strerror(errno));
784 r = -1;
785 goto EXIT;
786 }
787 r = gpt_get_state(fd, PRIMARY_GPT, &gpt_prim) ||
788 gpt_get_state(fd, SECONDARY_GPT, &gpt_second);
789 if (r) {
790 fprintf(stderr, "%s: Getting GPT headers state failed\n",
791 __func__);
792 goto EXIT;
793 }
794
795 /* These 2 combinations are unexpected and unacceptable */
796 if (gpt_prim == GPT_BAD_CRC || gpt_second == GPT_BAD_CRC) {
797 fprintf(stderr, "%s: GPT headers CRC corruption detected, aborting\n",
798 __func__);
799 r = -1;
800 goto EXIT;
801 }
802 if (gpt_prim == GPT_BAD_SIGNATURE && gpt_second == GPT_BAD_SIGNATURE) {
803 fprintf(stderr, "%s: Both GPT headers corrupted, aborting\n",
804 __func__);
805 r = -1;
806 goto EXIT;
807 }
808
809 /* Check internal update stage according GPT headers' state */
810 if (gpt_prim == GPT_OK && gpt_second == GPT_OK)
811 internal_stage = UPDATE_MAIN;
812 else if (gpt_prim == GPT_BAD_SIGNATURE)
813 internal_stage = UPDATE_BACKUP;
814 else if (gpt_second == GPT_BAD_SIGNATURE)
815 internal_stage = UPDATE_FINALIZE;
816 else {
817 fprintf(stderr, "%s: Abnormal GPTs state: primary (%d), secondary (%d), "
818 "aborting\n", __func__, gpt_prim, gpt_second);
819 r = -1;
820 goto EXIT;
821 }
822
823 /* Stage already set - ready for update, exitting */
824 if ((int) stage == (int) internal_stage - 1)
825 goto EXIT;
826 /* Unexpected stage given */
827 if (stage != internal_stage) {
828 r = -1;
829 goto EXIT;
830 }
831
832 switch (stage) {
833 case UPDATE_MAIN:
834 if (is_ufs) {
835 if(stat(XBL_PRIMARY, &xbl_partition_stat)||
836 stat(XBL_BACKUP, &xbl_partition_stat)){
837 //Non fatal error. Just means this target does not
838 //use XBL but relies on sbl whose update is handled
839 //by the normal methods.
840 fprintf(stderr, "%s: xbl part not found(%s).Assuming sbl in use\n",
841 __func__,
842 strerror(errno));
843 } else {
844 //Switch the boot lun so that backup boot LUN is used
845 r = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
846 if(r){
847 fprintf(stderr, "%s: Failed to set xbl backup partition as boot\n",
848 __func__);
849 goto EXIT;
850 }
851 }
852 }
853 //Fix up the backup GPT table so that it actually points to
854 //the backup copy of the boot critical images
855 fprintf(stderr, "%s: Preparing for primary partition update\n",
856 __func__);
857 r = gpt2_set_boot_chain(fd, BACKUP_BOOT);
858 if (r) {
859 if (r < 0)
860 fprintf(stderr,
861 "%s: Setting secondary GPT to backup boot failed\n",
862 __func__);
863 /* No backup partitions - do not corrupt GPT, do not flag error */
864 else
865 r = 0;
866 goto EXIT;
867 }
868 //corrupt the primary GPT so that the backup(which now points to
869 //the backup boot partitions is used)
870 r = gpt_set_state(fd, PRIMARY_GPT, GPT_BAD_SIGNATURE);
871 if (r) {
872 fprintf(stderr, "%s: Corrupting primary GPT header failed\n",
873 __func__);
874 goto EXIT;
875 }
876 break;
877 case UPDATE_BACKUP:
878 if (is_ufs) {
879 if(stat(XBL_PRIMARY, &xbl_partition_stat)||
880 stat(XBL_BACKUP, &xbl_partition_stat)){
881 //Non fatal error. Just means this target does not
882 //use XBL but relies on sbl whose update is handled
883 //by the normal methods.
884 fprintf(stderr, "%s: xbl part not found(%s).Assuming sbl in use\n",
885 __func__,
886 strerror(errno));
887 } else {
888 //Switch the boot lun so that backup boot LUN is used
889 r = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
890 if(r) {
891 fprintf(stderr, "%s: Failed to set xbl backup partition as boot\n",
892 __func__);
893 goto EXIT;
894 }
895 }
896 }
897 //Fix the primary GPT header so that is used
898 fprintf(stderr, "%s: Preparing for backup partition update\n",
899 __func__);
900 r = gpt_set_state(fd, PRIMARY_GPT, GPT_OK);
901 if (r) {
902 fprintf(stderr, "%s: Fixing primary GPT header failed\n",
903 __func__);
904 goto EXIT;
905 }
906 //Corrupt the scondary GPT header
907 r = gpt_set_state(fd, SECONDARY_GPT, GPT_BAD_SIGNATURE);
908 if (r) {
909 fprintf(stderr, "%s: Corrupting secondary GPT header failed\n",
910 __func__);
911 goto EXIT;
912 }
913 break;
914 case UPDATE_FINALIZE:
915 //Undo the changes we had made in the UPDATE_MAIN stage so that the
916 //primary/backup GPT headers once again point to the same set of
917 //partitions
918 fprintf(stderr, "%s: Finalizing partitions\n",
919 __func__);
920 r = gpt2_set_boot_chain(fd, NORMAL_BOOT);
921 if (r < 0) {
922 fprintf(stderr, "%s: Setting secondary GPT to normal boot failed\n",
923 __func__);
924 goto EXIT;
925 }
926
927 r = gpt_set_state(fd, SECONDARY_GPT, GPT_OK);
928 if (r) {
929 fprintf(stderr, "%s: Fixing secondary GPT header failed\n",
930 __func__);
931 goto EXIT;
932 }
933 break;
934 default:;
935 }
936
937EXIT:
938 if (fd >= 0) {
939 fsync(fd);
940 close(fd);
941 }
942 return r;
943}
944
945int add_lun_to_update_list(char *lun_path, struct update_data *dat)
946{
947 uint32_t i = 0;
948 struct stat st;
949 if (!lun_path || !dat){
950 fprintf(stderr, "%s: Invalid data",
951 __func__);
952 return -1;
953 }
954 if (stat(lun_path, &st)) {
955 fprintf(stderr, "%s: Unable to access %s. Skipping adding to list",
956 __func__,
957 lun_path);
958 return -1;
959 }
960 if (dat->num_valid_entries == 0) {
961 fprintf(stderr, "%s: Copying %s into lun_list[%d]\n",
962 __func__,
963 lun_path,
964 i);
965 strlcpy(dat->lun_list[0], lun_path,
966 PATH_MAX * sizeof(char));
967 dat->num_valid_entries = 1;
968 } else {
969 for (i = 0; (i < dat->num_valid_entries) &&
970 (dat->num_valid_entries < MAX_LUNS - 1); i++) {
971 //Check if the current LUN is not already part
972 //of the lun list
973 if (!strncmp(lun_path,dat->lun_list[i],
974 strlen(dat->lun_list[i]))) {
975 //LUN already in list..Return
976 return 0;
977 }
978 }
979 fprintf(stderr, "%s: Copying %s into lun_list[%d]\n",
980 __func__,
981 lun_path,
982 dat->num_valid_entries);
983 //Add LUN path lun list
984 strlcpy(dat->lun_list[dat->num_valid_entries], lun_path,
985 PATH_MAX * sizeof(char));
986 dat->num_valid_entries++;
987 }
988 return 0;
989}
990
991int prepare_boot_update(enum boot_update_stage stage)
992{
micky387e96abca2019-06-11 02:35:20 +0200993 int is_ufs = gpt_utils_is_ufs_device();
994 struct stat ufs_dir_stat;
995 struct update_data data;
996 int rcode = 0;
997 uint32_t i = 0;
998 int is_error = 0;
999 const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
1000 //Holds /dev/block/bootdevice/by-name/*bak entry
1001 char buf[PATH_MAX] = {0};
1002 //Holds the resolved path of the symlink stored in buf
1003 char real_path[PATH_MAX] = {0};
1004
1005 if (!is_ufs) {
1006 //emmc device. Just pass in path to mmcblk0
1007 return prepare_partitions(stage, BLK_DEV_FILE);
1008 } else {
1009 //Now we need to find the list of LUNs over
1010 //which the boot critical images are spread
1011 //and set them up for failsafe updates.To do
1012 //this we find out where the symlinks for the
1013 //each of the paths under
1014 ///dev/block/bootdevice/by-name/PTN_SWAP_LIST
1015 //actually point to.
1016 fprintf(stderr, "%s: Running on a UFS device\n",
1017 __func__);
1018 memset(&data, '\0', sizeof(struct update_data));
1019 for (i=0; i < ARRAY_SIZE(ptn_swap_list); i++) {
1020 //XBL on UFS does not follow the convention
1021 //of being loaded based on well known GUID'S.
1022 //We take care of switching the UFS boot LUN
1023 //explicitly later on.
1024 if (!strncmp(ptn_swap_list[i],
1025 PTN_XBL,
1026 strlen(PTN_XBL)))
1027 continue;
1028 snprintf(buf, sizeof(buf),
1029 "%s/%sbak",
1030 BOOT_DEV_DIR,
1031 ptn_swap_list[i]);
1032 if (stat(buf, &ufs_dir_stat)) {
1033 continue;
1034 }
1035 if (readlink(buf, real_path, sizeof(real_path) - 1) < 0)
1036 {
1037 fprintf(stderr, "%s: readlink error. Skipping %s",
1038 __func__,
1039 strerror(errno));
1040 } else {
1041 if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
1042 fprintf(stderr, "Unknown path.Skipping :%s:\n",
1043 real_path);
1044 } else {
1045 real_path[PATH_TRUNCATE_LOC] = '\0';
1046 add_lun_to_update_list(real_path, &data);
1047 }
1048 }
1049 memset(buf, '\0', sizeof(buf));
1050 memset(real_path, '\0', sizeof(real_path));
1051 }
1052 for (i=0; i < data.num_valid_entries; i++) {
1053 fprintf(stderr, "%s: Preparing %s for update stage %d\n",
1054 __func__,
1055 data.lun_list[i],
1056 stage);
1057 rcode = prepare_partitions(stage, data.lun_list[i]);
1058 if (rcode != 0)
1059 {
1060 fprintf(stderr, "%s: Failed to prepare %s.Continuing..\n",
1061 __func__,
1062 data.lun_list[i]);
1063 is_error = 1;
1064 }
1065 }
1066 }
1067 if (is_error)
1068 return -1;
1069 return 0;
1070}
1071
1072//Given a parttion name(eg: rpm) get the path to the block device that
1073//represents the GPT disk the partition resides on. In the case of emmc it
1074//would be the default emmc dev(/dev/block/mmcblk0). In the case of UFS we look
1075//through the /dev/block/bootdevice/by-name/ tree for partname, and resolve
1076//the path to the LUN from there.
1077static int get_dev_path_from_partition_name(const char *partname,
1078 char *buf,
1079 size_t buflen)
1080{
1081 struct stat st;
1082 char path[PATH_MAX] = {0};
1083 if (!partname || !buf || buflen < ((PATH_TRUNCATE_LOC) + 1)) {
1084 ALOGE("%s: Invalid argument", __func__);
1085 goto error;
1086 }
1087 if (gpt_utils_is_ufs_device()) {
1088 //Need to find the lun that holds partition partname
1089 snprintf(path, sizeof(path),
1090 "%s/%s",
1091 BOOT_DEV_DIR,
1092 partname);
1093 if (stat(path, &st)) {
1094 goto error;
1095 }
1096 if (readlink(path, buf, buflen) < 0)
1097 {
1098 goto error;
1099 } else {
1100 buf[PATH_TRUNCATE_LOC] = '\0';
1101 }
1102 } else {
1103 snprintf(buf, buflen, BLK_DEV_FILE);
1104 }
1105 return 0;
1106
1107error:
1108 return -1;
1109}
1110
1111int gpt_utils_get_partition_map(vector<string>& ptn_list,
1112 map<string, vector<string>>& partition_map) {
1113 char devpath[PATH_MAX] = {'\0'};
1114 map<string, vector<string>>::iterator it;
1115 if (ptn_list.size() < 1) {
1116 fprintf(stderr, "%s: Invalid ptn list\n", __func__);
1117 goto error;
1118 }
1119 //Go through the passed in list
1120 for (uint32_t i = 0; i < ptn_list.size(); i++)
1121 {
1122 //Key in the map is the path to the device that holds the
1123 //partition
1124 if (get_dev_path_from_partition_name(ptn_list[i].c_str(),
1125 devpath,
1126 sizeof(devpath))) {
1127 //Not necessarily an error. The partition may just
1128 //not be present.
1129 continue;
1130 }
1131 string path = devpath;
1132 it = partition_map.find(path);
1133 if (it != partition_map.end()) {
1134 it->second.push_back(ptn_list[i]);
1135 } else {
1136 vector<string> str_vec;
1137 str_vec.push_back( ptn_list[i]);
1138 partition_map.insert(pair<string, vector<string>>
1139 (path, str_vec));
1140 }
1141 memset(devpath, '\0', sizeof(devpath));
1142 }
1143 return 0;
1144error:
1145 return -1;
1146}
1147
1148//Get the block size of the disk represented by decsriptor fd
1149static uint32_t gpt_get_block_size(int fd)
1150{
1151 uint32_t block_size = 0;
1152 if (fd < 0) {
1153 ALOGE("%s: invalid descriptor",
1154 __func__);
1155 goto error;
1156 }
1157 if (ioctl(fd, BLKSSZGET, &block_size) != 0) {
1158 ALOGE("%s: Failed to get GPT dev block size : %s",
1159 __func__,
1160 strerror(errno));
1161 goto error;
1162 }
1163 return block_size;
1164error:
1165 return 0;
1166}
1167
1168//Write the GPT header present in the passed in buffer back to the
1169//disk represented by fd
1170static int gpt_set_header(uint8_t *gpt_header, int fd,
1171 enum gpt_instance instance)
1172{
1173 uint32_t block_size = 0;
1174 off64_t gpt_header_offset = 0;
1175 if (!gpt_header || fd < 0) {
1176 ALOGE("%s: Invalid arguments",
1177 __func__);
1178 goto error;
1179 }
1180 block_size = gpt_get_block_size(fd);
1181 if (block_size == 0) {
1182 ALOGE("%s: Failed to get block size", __func__);
1183 goto error;
1184 }
1185 if (instance == PRIMARY_GPT)
1186 gpt_header_offset = block_size;
1187 else
1188 gpt_header_offset = lseek64(fd, 0, SEEK_END) - block_size;
1189 if (gpt_header_offset <= 0) {
1190 ALOGE("%s: Failed to get gpt header offset",__func__);
1191 goto error;
1192 }
1193 if (blk_rw(fd, 1, gpt_header_offset, gpt_header, block_size)) {
1194 ALOGE("%s: Failed to write back GPT header", __func__);
1195 goto error;
1196 }
1197 return 0;
1198error:
1199 return -1;
1200}
1201
1202//Read out the GPT header for the disk that contains the partition partname
1203static uint8_t* gpt_get_header(const char *partname, enum gpt_instance instance)
1204{
1205 uint8_t* hdr = NULL;
1206 char devpath[PATH_MAX] = {0};
1207 int64_t hdr_offset = 0;
1208 uint32_t block_size = 0;
1209 int fd = -1;
1210 if (!partname) {
1211 ALOGE("%s: Invalid partition name", __func__);
1212 goto error;
1213 }
1214 if (get_dev_path_from_partition_name(partname, devpath, sizeof(devpath))
1215 != 0) {
1216 ALOGE("%s: Failed to resolve path for %s",
1217 __func__,
1218 partname);
1219 goto error;
1220 }
1221 fd = open(devpath, O_RDWR);
1222 if (fd < 0) {
1223 ALOGE("%s: Failed to open %s : %s",
1224 __func__,
1225 devpath,
1226 strerror(errno));
1227 goto error;
1228 }
1229 block_size = gpt_get_block_size(fd);
1230 if (block_size == 0)
1231 {
1232 ALOGE("%s: Failed to get gpt block size for %s",
1233 __func__,
1234 partname);
1235 goto error;
1236 }
1237
1238 hdr = (uint8_t*)malloc(block_size);
1239 if (!hdr) {
1240 ALOGE("%s: Failed to allocate memory for gpt header",
1241 __func__);
1242 }
1243 if (instance == PRIMARY_GPT)
1244 hdr_offset = block_size;
1245 else {
1246 hdr_offset = lseek64(fd, 0, SEEK_END) - block_size;
1247 }
1248 if (hdr_offset < 0) {
1249 ALOGE("%s: Failed to get gpt header offset",
1250 __func__);
1251 goto error;
1252 }
1253 if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) {
1254 ALOGE("%s: Failed to read GPT header from device",
1255 __func__);
1256 goto error;
1257 }
1258 close(fd);
1259 return hdr;
1260error:
1261 if (fd >= 0)
1262 close(fd);
1263 if (hdr)
1264 free(hdr);
1265 return NULL;
1266}
1267
1268//Returns the partition entry array based on the
1269//passed in buffer which contains the gpt header.
1270//The fd here is the descriptor for the 'disk' which
1271//holds the partition
1272static uint8_t* gpt_get_pentry_arr(uint8_t *hdr, int fd)
1273{
1274 uint64_t pentries_start = 0;
1275 uint32_t pentry_size = 0;
1276 uint32_t block_size = 0;
1277 uint32_t pentries_arr_size = 0;
1278 uint8_t *pentry_arr = NULL;
1279 int rc = 0;
1280 if (!hdr) {
1281 ALOGE("%s: Invalid header", __func__);
1282 goto error;
1283 }
1284 if (fd < 0) {
1285 ALOGE("%s: Invalid fd", __func__);
1286 goto error;
1287 }
1288 block_size = gpt_get_block_size(fd);
1289 if (!block_size) {
1290 ALOGE("%s: Failed to get gpt block size for",
1291 __func__);
1292 goto error;
1293 }
1294 pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
1295 pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
1296 pentries_arr_size =
1297 GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
1298 pentry_arr = (uint8_t*)calloc(1, pentries_arr_size);
1299 if (!pentry_arr) {
1300 ALOGE("%s: Failed to allocate memory for partition array",
1301 __func__);
1302 goto error;
1303 }
1304 rc = blk_rw(fd, 0,
1305 pentries_start,
1306 pentry_arr,
1307 pentries_arr_size);
1308 if (rc) {
1309 ALOGE("%s: Failed to read partition entry array",
1310 __func__);
1311 goto error;
1312 }
1313 return pentry_arr;
1314error:
1315 if (pentry_arr)
1316 free(pentry_arr);
1317 return NULL;
1318}
1319
1320static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t* arr)
1321{
1322 uint32_t block_size = 0;
1323 uint64_t pentries_start = 0;
1324 uint32_t pentry_size = 0;
1325 uint32_t pentries_arr_size = 0;
1326 int rc = 0;
1327 if (!hdr || fd < 0 || !arr) {
1328 ALOGE("%s: Invalid argument", __func__);
1329 goto error;
1330 }
1331 block_size = gpt_get_block_size(fd);
1332 if (!block_size) {
1333 ALOGE("%s: Failed to get gpt block size for",
1334 __func__);
1335 goto error;
1336 }
1337 pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
1338 pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
1339 pentries_arr_size =
1340 GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
1341 rc = blk_rw(fd, 1,
1342 pentries_start,
1343 arr,
1344 pentries_arr_size);
1345 if (rc) {
1346 ALOGE("%s: Failed to read partition entry array",
1347 __func__);
1348 goto error;
1349 }
1350 return 0;
1351error:
1352 return -1;
1353}
1354
1355
1356
1357//Allocate a handle used by calls to the "gpt_disk" api's
1358struct gpt_disk * gpt_disk_alloc()
1359{
1360 struct gpt_disk *disk;
1361 disk = (struct gpt_disk *)malloc(sizeof(struct gpt_disk));
1362 if (!disk) {
1363 ALOGE("%s: Failed to allocate memory", __func__);
1364 goto end;
1365 }
1366 memset(disk, 0, sizeof(struct gpt_disk));
1367end:
1368 return disk;
1369}
1370
1371//Free previously allocated/initialized handle
1372void gpt_disk_free(struct gpt_disk *disk)
1373{
1374 if (!disk)
1375 return;
1376 if (disk->hdr)
1377 free(disk->hdr);
1378 if (disk->hdr_bak)
1379 free(disk->hdr_bak);
1380 if (disk->pentry_arr)
1381 free(disk->pentry_arr);
1382 if (disk->pentry_arr_bak)
1383 free(disk->pentry_arr_bak);
1384 free(disk);
1385 return;
1386}
1387
1388//fills up the passed in gpt_disk struct with information about the
1389//disk represented by path dev. Returns 0 on success and -1 on error.
1390int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk)
1391{
micky387e96abca2019-06-11 02:35:20 +02001392
LuK133788dd8102020-04-06 12:45:17 +02001393 struct gpt_disk *disk = NULL;
1394 int fd = -1;
1395 uint32_t gpt_header_size = 0;
1396 uint32_t crc_zero;
1397
1398 crc_zero = crc32(0L, Z_NULL, 0);
micky387e96abca2019-06-11 02:35:20 +02001399 if (!dsk || !dev) {
1400 ALOGE("%s: Invalid arguments", __func__);
1401 goto error;
1402 }
1403 disk = dsk;
1404 disk->hdr = gpt_get_header(dev, PRIMARY_GPT);
1405 if (!disk->hdr) {
1406 ALOGE("%s: Failed to get primary header", __func__);
1407 goto error;
1408 }
1409 gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
LuK133788dd8102020-04-06 12:45:17 +02001410 disk->hdr_crc = crc32(crc_zero, disk->hdr, gpt_header_size);
micky387e96abca2019-06-11 02:35:20 +02001411 disk->hdr_bak = gpt_get_header(dev, SECONDARY_GPT);
1412 if (!disk->hdr_bak) {
1413 ALOGE("%s: Failed to get backup header", __func__);
1414 goto error;
1415 }
LuK133788dd8102020-04-06 12:45:17 +02001416 disk->hdr_bak_crc = crc32(crc_zero, disk->hdr_bak, gpt_header_size);
micky387e96abca2019-06-11 02:35:20 +02001417
1418 //Descriptor for the block device. We will use this for further
1419 //modifications to the partition table
1420 if (get_dev_path_from_partition_name(dev,
1421 disk->devpath,
1422 sizeof(disk->devpath)) != 0) {
1423 ALOGE("%s: Failed to resolve path for %s",
1424 __func__,
1425 dev);
1426 goto error;
1427 }
1428 fd = open(disk->devpath, O_RDWR);
1429 if (fd < 0) {
1430 ALOGE("%s: Failed to open %s: %s",
1431 __func__,
1432 disk->devpath,
1433 strerror(errno));
1434 goto error;
1435 }
1436 disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd);
1437 if (!disk->pentry_arr) {
1438 ALOGE("%s: Failed to obtain partition entry array",
1439 __func__);
1440 goto error;
1441 }
1442 disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd);
1443 if (!disk->pentry_arr_bak) {
1444 ALOGE("%s: Failed to obtain backup partition entry array",
1445 __func__);
1446 goto error;
1447 }
1448 disk->pentry_size = GET_4_BYTES(disk->hdr + PENTRY_SIZE_OFFSET);
1449 disk->pentry_arr_size =
1450 GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) *
1451 disk->pentry_size;
1452 disk->pentry_arr_crc = GET_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET);
1453 disk->pentry_arr_bak_crc = GET_4_BYTES(disk->hdr_bak +
1454 PARTITION_CRC_OFFSET);
1455 disk->block_size = gpt_get_block_size(fd);
1456 close(fd);
1457 disk->is_initialized = GPT_DISK_INIT_MAGIC;
1458 return 0;
1459error:
1460 if (fd >= 0)
1461 close(fd);
1462 return -1;
1463}
1464
1465//Get pointer to partition entry from a allocated gpt_disk structure
1466uint8_t* gpt_disk_get_pentry(struct gpt_disk *disk,
1467 const char *partname,
1468 enum gpt_instance instance)
1469{
1470 uint8_t *ptn_arr = NULL;
1471 if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) {
1472 ALOGE("%s: Invalid argument",__func__);
1473 goto error;
1474 }
1475 ptn_arr = (instance == PRIMARY_GPT) ?
1476 disk->pentry_arr : disk->pentry_arr_bak;
1477 return (gpt_pentry_seek(partname, ptn_arr,
1478 ptn_arr + disk->pentry_arr_size ,
1479 disk->pentry_size));
1480error:
1481 return NULL;
1482}
1483
1484//Update CRC values for the various components of the gpt_disk
1485//structure. This function should be called after any of the fields
1486//have been updated before the structure contents are written back to
1487//disk.
1488int gpt_disk_update_crc(struct gpt_disk *disk)
1489{
1490 uint32_t gpt_header_size = 0;
LuK133788dd8102020-04-06 12:45:17 +02001491 uint32_t crc_zero;
1492 crc_zero = crc32(0L, Z_NULL, 0);
micky387e96abca2019-06-11 02:35:20 +02001493 if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) {
1494 ALOGE("%s: invalid argument", __func__);
1495 goto error;
1496 }
1497 //Recalculate the CRC of the primary partiton array
LuK133788dd8102020-04-06 12:45:17 +02001498 disk->pentry_arr_crc = crc32(crc_zero,
micky387e96abca2019-06-11 02:35:20 +02001499 disk->pentry_arr,
1500 disk->pentry_arr_size);
1501 //Recalculate the CRC of the backup partition array
LuK133788dd8102020-04-06 12:45:17 +02001502 disk->pentry_arr_bak_crc = crc32(crc_zero,
micky387e96abca2019-06-11 02:35:20 +02001503 disk->pentry_arr_bak,
1504 disk->pentry_arr_size);
1505 //Update the partition CRC value in the primary GPT header
1506 PUT_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET, disk->pentry_arr_crc);
1507 //Update the partition CRC value in the backup GPT header
1508 PUT_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET,
1509 disk->pentry_arr_bak_crc);
1510 //Update the CRC value of the primary header
1511 gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
1512 //Header CRC is calculated with its own CRC field set to 0
1513 PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, 0);
1514 PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, 0);
LuK133788dd8102020-04-06 12:45:17 +02001515 disk->hdr_crc = crc32(crc_zero, disk->hdr, gpt_header_size);
1516 disk->hdr_bak_crc = crc32(crc_zero, disk->hdr_bak, gpt_header_size);
micky387e96abca2019-06-11 02:35:20 +02001517 PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, disk->hdr_crc);
1518 PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, disk->hdr_bak_crc);
1519 return 0;
1520error:
1521 return -1;
1522}
1523
1524//Write the contents of struct gpt_disk back to the actual disk
1525int gpt_disk_commit(struct gpt_disk *disk)
1526{
1527 int fd = -1;
1528 if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)){
1529 ALOGE("%s: Invalid args", __func__);
1530 goto error;
1531 }
1532 fd = open(disk->devpath, O_RDWR);
1533 if (fd < 0) {
1534 ALOGE("%s: Failed to open %s: %s",
1535 __func__,
1536 disk->devpath,
1537 strerror(errno));
1538 goto error;
1539 }
1540 //Write the primary header
1541 if(gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) {
1542 ALOGE("%s: Failed to update primary GPT header",
1543 __func__);
1544 goto error;
1545 }
1546 //Write back the primary partition array
1547 if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) {
1548 ALOGE("%s: Failed to write primary GPT partition arr",
1549 __func__);
1550 goto error;
1551 }
1552 //Write back the secondary header
1553 if(gpt_set_header(disk->hdr_bak, fd, SECONDARY_GPT) != 0) {
1554 ALOGE("%s: Failed to update secondary GPT header",
1555 __func__);
1556 goto error;
1557 }
1558 //Write back the secondary partition array
1559 if (gpt_set_pentry_arr(disk->hdr_bak, fd, disk->pentry_arr_bak)) {
1560 ALOGE("%s: Failed to write secondary GPT partition arr",
1561 __func__);
1562 goto error;
1563 }
1564 close(fd);
1565 return 0;
1566error:
1567 if (fd >= 0)
1568 close(fd);
1569 return -1;
1570}