1a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan// Use of this source code is governed by a BSD-style license that can be
3a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan// found in the LICENSE file.
4a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
5a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan#include <string.h>
6a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
75fed2a667096341160db8643a4a057e328953a1dBill Richardson#define _STUB_IMPLEMENTATION_
80c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson
90c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "cgpt.h"
100c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "cgpt_params.h"
110c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "cgptlib_internal.h"
125fed2a667096341160db8643a4a057e328953a1dBill Richardson#include "utility.h"
130c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "vboot_host.h"
1466b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo
1566b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lostatic const char* DumpCgptAddParams(const CgptAddParams *params) {
1666b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  static char buf[256];
1766b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  char tmp[64];
1866b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo
1966b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  buf[0] = 0;
2066b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  snprintf(tmp, sizeof(tmp), "-i %d ", params->partition);
215fed2a667096341160db8643a4a057e328953a1dBill Richardson  StrnAppend(buf, tmp, sizeof(buf));
2266b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->label) {
2366b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-l %s ", params->label);
245fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
2566b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
2666b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_begin) {
2766b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-b %llu ", (unsigned long long)params->begin);
285fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
2966b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
3066b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_size) {
3166b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-s %llu ", (unsigned long long)params->size);
325fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
3366b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
3466b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_type) {
3566b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    GuidToStr(&params->type_guid, tmp, sizeof(tmp));
365fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, "-t ", sizeof(buf));
375fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
385fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, " ", sizeof(buf));
3966b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
4066b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_unique) {
4166b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    GuidToStr(&params->unique_guid, tmp, sizeof(tmp));
425fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, "-u ", sizeof(buf));
435fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
445fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, " ", sizeof(buf));
4566b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
4666b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_successful) {
4766b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-S %d ", params->successful);
485fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
4966b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
5066b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_tries) {
5166b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-T %d ", params->tries);
525fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
5366b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
5466b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_priority) {
5566b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-P %d ", params->priority);
565fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
5766b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
5866b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  if (params->set_raw) {
5966b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo    snprintf(tmp, sizeof(tmp), "-A 0x%x ", params->raw_value);
605fed2a667096341160db8643a4a057e328953a1dBill Richardson    StrnAppend(buf, tmp, sizeof(buf));
6166b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  }
6266b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo
635fed2a667096341160db8643a4a057e328953a1dBill Richardson  StrnAppend(buf, "\n", sizeof(buf));
6466b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo  return buf;
6566b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo}
6666b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo
67fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk// This is the implementation-specific helper function.
68fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulkstatic int GptSetEntryAttributes(struct drive *drive,
69250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan                                 uint32_t index,
70250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan                                 CgptAddParams *params) {
71fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  GptEntry *entry;
72fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk
73fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  entry = GetEntry(&drive->gpt, PRIMARY, index);
74fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->set_begin)
75fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    entry->starting_lba = params->begin;
76fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->set_size)
77fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    entry->ending_lba = entry->starting_lba + params->size - 1;
78fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->set_unique) {
79fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    memcpy(&entry->unique, &params->unique_guid, sizeof(Guid));
80fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  } else if (GuidIsZero(&entry->type)) {
814cb5497984642b8cbd592c14cb1912a787b2d4d7Bill Richardson	  if (CGPT_OK != GenerateGuid(&entry->unique)) {
824cb5497984642b8cbd592c14cb1912a787b2d4d7Bill Richardson		  Error("Unable to generate new GUID.\n");
834cb5497984642b8cbd592c14cb1912a787b2d4d7Bill Richardson		  return -1;
84fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    }
85fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  }
86fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->set_type)
87fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    memcpy(&entry->type, &params->type_guid, sizeof(Guid));
88fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->label) {
89fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    if (CGPT_OK != UTF8ToUTF16((uint8_t *)params->label, entry->name,
90fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk                               sizeof(entry->name) / sizeof(entry->name[0]))) {
91fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      Error("The label cannot be converted to UTF16.\n");
92fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      return -1;
93fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    }
94fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  }
95fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  return 0;
96fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk}
97fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk
98fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk// This is an internal helper function which assumes no NULL args are passed.
99fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk// It sets the given attribute values for a single entry at the given index.
100fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulkstatic int SetEntryAttributes(struct drive *drive,
101fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk                              uint32_t index,
102fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk                              CgptAddParams *params) {
103250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  if (params->set_raw) {
104fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    SetRaw(drive, PRIMARY, index, params->raw_value);
105250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  } else {
106250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    if (params->set_successful)
107fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      SetSuccessful(drive, PRIMARY, index, params->successful);
108250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    if (params->set_tries)
109fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      SetTries(drive, PRIMARY, index, params->tries);
110250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    if (params->set_priority)
111fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      SetPriority(drive, PRIMARY, index, params->priority);
112250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
113a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
114fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  // New partitions must specify type, begin, and size.
115fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (IsUnused(drive, PRIMARY, index)) {
116fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    if (!params->set_begin || !params->set_size || !params->set_type) {
117fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      Error("-t, -b, and -s options are required for new partitions\n");
118fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      return -1;
119fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    }
120fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    if (GuidIsZero(&params->type_guid)) {
121fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      Error("New partitions must have a type other than \"unused\"\n");
122fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      return -1;
123fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    }
124fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  }
125a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
126fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  return 0;
127fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk}
128a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
129fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulkstatic int CgptCheckAddValidity(struct drive *drive) {
1308577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  int gpt_retval;
1318577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
1328577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen    Error("GptSanityCheck() returned %d: %s\n",
1338577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen          gpt_retval, GptError(gpt_retval));
1348577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen    return -1;
1358577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  }
136a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
1378577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  if (((drive->gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
1388577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen      ((drive->gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
1398577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen    Error("one of the GPT header/entries is invalid.\n"
1408577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen          "please run 'cgpt repair' before adding anything.\n");
1418577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen    return -1;
142250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
1438577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen
144fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  return 0;
145fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk}
146250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
147fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulkstatic int CgptGetUnusedPartition(struct drive *drive, uint32_t *index,
148fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk                                  CgptAddParams *params) {
149fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  uint32_t i;
150fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  uint32_t max_part = GetNumberOfEntries(drive);
151fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->partition) {
152fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    if (params->partition > max_part) {
153fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      Error("invalid partition number: %d\n", params->partition);
154fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      return -1;
155fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    }
156fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    *index = params->partition - 1;
157fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    return 0;
158fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  } else {
159fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    // Find next empty partition.
160fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    for (i = 0; i < max_part; i++) {
161fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      if (IsUnused(drive, PRIMARY, i)) {
162fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk        params->partition = i + 1;
163fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk        *index = i;
164fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk        return 0;
165fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      }
166fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    }
167fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    Error("no unused partitions available\n");
168fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    return -1;
169fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  }
170fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk}
171fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk
172fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulkint CgptSetAttributes(CgptAddParams *params) {
173fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  struct drive drive;
174fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk
175fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params == NULL)
176fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    return CGPT_FAILED;
177fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk
178ab899591808dd3e5f955ab7693b54a83389cd35fNam T. Nguyen  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR,
179ab899591808dd3e5f955ab7693b54a83389cd35fNam T. Nguyen                           params->drive_size))
180fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    return CGPT_FAILED;
181fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk
182fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (CgptCheckAddValidity(&drive)) {
183250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    goto bad;
184250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
185250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
186fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->partition == 0 ||
187fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      params->partition >= GetNumberOfEntries(&drive)) {
188250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    Error("invalid partition number: %d\n", params->partition);
189250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    goto bad;
190250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
191250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
192fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  SetEntryAttributes(&drive, params->partition - 1, params);
193250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
194fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  UpdateAllEntries(&drive);
195250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
196250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  // Write it all out.
197250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  return DriveClose(&drive, 1);
198250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
199250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasanbad:
200250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  DriveClose(&drive, 0);
201250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  return CGPT_FAILED;
202250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan}
203250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
204250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan// This method gets the partition details such as the attributes, the
205250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan// guids of the partitions, etc. Input is the partition number or the
206250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan// unique id of the partition. Output is populated in the respective
207250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan// fields of params.
2083f806a2abf07d7b801852a4a6f3a9080a4b5c427Bill Richardsonint CgptGetPartitionDetails(CgptAddParams *params) {
209250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  struct drive drive;
210250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  int result = CGPT_FAILED;
211fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  int index;
212250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
213250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  if (params == NULL)
214fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    return CGPT_FAILED;
215250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
216ab899591808dd3e5f955ab7693b54a83389cd35fNam T. Nguyen  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR,
217ab899591808dd3e5f955ab7693b54a83389cd35fNam T. Nguyen                           params->drive_size))
218fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    return CGPT_FAILED;
219250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
220fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (CgptCheckAddValidity(&drive)) {
221250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    goto bad;
222250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
223250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
224fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  int max_part = GetNumberOfEntries(&drive);
225fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (params->partition > 0) {
226fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk    if (params->partition >= max_part) {
227250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      Error("invalid partition number: %d\n", params->partition);
228250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      goto bad;
229250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    }
230250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  } else {
231250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    if (!params->set_unique) {
232250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      Error("either partition or unique_id must be specified\n");
233250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      goto bad;
234250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    }
235250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    for (index = 0; index < max_part; index++) {
236fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk      GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
237250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      if (GuidEqual(&entry->unique, &params->unique_guid)) {
238250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan        params->partition = index + 1;
239250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan        break;
240250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      }
241250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    }
242250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    if (index >= max_part) {
243250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      Error("no partitions with the given unique id available\n");
244250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan      goto bad;
245250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    }
246250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
247fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  index = params->partition - 1;
248250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
2498577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  // GPT-specific code
2508577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
2518577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  params->begin = entry->starting_lba;
2528577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  params->size =  entry->ending_lba - entry->starting_lba + 1;
2538577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  memcpy(&params->type_guid, &entry->type, sizeof(Guid));
2548577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  memcpy(&params->unique_guid, &entry->unique, sizeof(Guid));
2558577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  params->raw_value = entry->attrs.fields.gpt_att;
256250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
257fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  params->successful = GetSuccessful(&drive, PRIMARY, index);
258fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  params->tries = GetTries(&drive, PRIMARY, index);
259fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  params->priority = GetPriority(&drive, PRIMARY, index);
260250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  result = CGPT_OK;
261250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
262250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasanbad:
263250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  DriveClose(&drive, 0);
264250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  return result;
265250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan}
266250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
26718e03706df6ab4256a89f4e578ecf0f165641c8aBill Richardsonstatic int GptAdd(struct drive *drive, CgptAddParams *params, uint32_t index) {
2687d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  GptEntry *entry, backup;
2697d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  int rv;
2707d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2717d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  entry = GetEntry(&drive->gpt, PRIMARY, index);
2727d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  memcpy(&backup, entry, sizeof(backup));
2737d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2747d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  if (SetEntryAttributes(drive, index, params) ||
2757d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk      GptSetEntryAttributes(drive, index, params)) {
2767d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    memcpy(entry, &backup, sizeof(*entry));
2777d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    return -1;
2787d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  }
2797d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2807d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  UpdateAllEntries(drive);
2817d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2827d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  rv = CheckEntries((GptEntry*)drive->gpt.primary_entries,
2837d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk                    (GptHeader*)drive->gpt.primary_header);
2847d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2857d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  if (0 != rv) {
2867d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    // If the modified entry is illegal, recover it and return error.
2877d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    memcpy(entry, &backup, sizeof(*entry));
2887d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    Error("%s\n", GptErrorText(rv));
2897d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    Error(DumpCgptAddParams(params));
2907d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk    return -1;
2917d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  }
2927d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2937d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk  return 0;
2947d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk}
2957d401c5cd58ec422e239b28c334fc2e94778f565Albert Chaulk
2963f806a2abf07d7b801852a4a6f3a9080a4b5c427Bill Richardsonint CgptAdd(CgptAddParams *params) {
297250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  struct drive drive;
298250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  uint32_t index;
299250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
300250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  if (params == NULL)
301250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    return CGPT_FAILED;
302250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
303ab899591808dd3e5f955ab7693b54a83389cd35fNam T. Nguyen  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR,
304ab899591808dd3e5f955ab7693b54a83389cd35fNam T. Nguyen                           params->drive_size))
305a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan    return CGPT_FAILED;
306250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
307fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (CgptCheckAddValidity(&drive)) {
308250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    goto bad;
309250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  }
310250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan
311fa6b35c1ffa33833b3250a6515869ccd4cb59121Albert Chaulk  if (CgptGetUnusedPartition(&drive, &index, params)) {
312250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan    goto bad;
313a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan  }
314a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
3158577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen  if (GptAdd(&drive, params, index))
3168577b5360ca4c9514d9091ed9aded2bb3193f1f0Nam T. Nguyen    goto bad;
31766b47ba37d3658cceecf30d25edc3becbb692c4aLouis Yung-Chieh Lo
318250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  // Write it all out.
319a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan  return DriveClose(&drive, 1);
320a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan
321a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasanbad:
322250549d3e742cddaf72b4f53d5739e54faf5db96Jay Srinivasan  DriveClose(&drive, 0);
323a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan  return CGPT_FAILED;
324a05814398202c4147a5e3f28474830ec0a9a0a90Jay Srinivasan}
325