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