cgpt_prioritize.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <string.h>
  5. #include "cgpt.h"
  6. #include "cgptlib_internal.h"
  7. #include "vboot_host.h"
  8. //////////////////////////////////////////////////////////////////////////////
  9. // We need a sorted list of priority groups, where each element in the list
  10. // contains an unordered list of GPT partition numbers.
  11. #define MAX_GROUPS 17 // 0-15, plus one "higher"
  12. typedef struct {
  13. int priority; // priority of this group
  14. int num_parts; // number of partitions in this group
  15. uint32_t *part; // array of partitions in this group
  16. } group_t;
  17. typedef struct {
  18. int max_parts; // max number of partitions in any group
  19. int num_groups; // number of non-empty groups
  20. group_t group[MAX_GROUPS]; // array of groups
  21. } group_list_t;
  22. static group_list_t *NewGroupList(int max_p) {
  23. int i;
  24. group_list_t *gl = (group_list_t *)malloc(sizeof(group_list_t));
  25. require(gl);
  26. gl->max_parts = max_p;
  27. gl->num_groups = 0;
  28. // reserve space for the maximum number of partitions in every group
  29. for (i=0; i<MAX_GROUPS; i++) {
  30. gl->group[i].priority = -1;
  31. gl->group[i].num_parts = 0;
  32. gl->group[i].part = (uint32_t *)malloc(sizeof(uint32_t) * max_p);
  33. require(gl->group[i].part);
  34. }
  35. return gl;
  36. }
  37. static void FreeGroups(group_list_t *gl) {
  38. int i;
  39. for (i=0; i<MAX_GROUPS; i++)
  40. free(gl->group[i].part);
  41. free(gl);
  42. }
  43. static void AddToGroup(group_list_t *gl, int priority, int partition) {
  44. int i;
  45. // See if I've already got a group with this priority
  46. for (i=0; i<gl->num_groups; i++)
  47. if (gl->group[i].priority == priority)
  48. break;
  49. if (i == gl->num_groups) {
  50. // no, add a group
  51. require(i < MAX_GROUPS);
  52. gl->num_groups++;
  53. gl->group[i].priority = priority;
  54. }
  55. // add the partition to it
  56. int j = gl->group[i].num_parts;
  57. gl->group[i].part[j] = partition;
  58. gl->group[i].num_parts++;
  59. }
  60. static void ChangeGroup(group_list_t *gl, int old_priority, int new_priority) {
  61. int i;
  62. for (i=0; i<gl->num_groups; i++)
  63. if (gl->group[i].priority == old_priority) {
  64. gl->group[i].priority = new_priority;
  65. break;
  66. }
  67. }
  68. static void SortGroups(group_list_t *gl) {
  69. int i, j;
  70. group_t tmp;
  71. // straight insertion sort is fast enough
  72. for (i=1; i<gl->num_groups; i++) {
  73. tmp = gl->group[i];
  74. for (j=i; j && (gl->group[j-1].priority < tmp.priority); j--)
  75. gl->group[j] = gl->group[j-1];
  76. gl->group[j] = tmp;
  77. }
  78. }
  79. int CgptPrioritize(CgptPrioritizeParams *params) {
  80. struct drive drive;
  81. int priority;
  82. int gpt_retval;
  83. uint32_t index;
  84. uint32_t max_part;
  85. int num_kernels;
  86. int i,j;
  87. group_list_t *groups;
  88. if (params == NULL)
  89. return CGPT_FAILED;
  90. if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR,
  91. params->drive_size))
  92. return CGPT_FAILED;
  93. if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
  94. Error("GptSanityCheck() returned %d: %s\n",
  95. gpt_retval, GptError(gpt_retval));
  96. return CGPT_FAILED;
  97. }
  98. max_part = GetNumberOfEntries(&drive);
  99. if (params->set_partition) {
  100. if (params->set_partition < 1 || params->set_partition > max_part) {
  101. Error("invalid partition number: %d (must be between 1 and %d\n",
  102. params->set_partition, max_part);
  103. goto bad;
  104. }
  105. index = params->set_partition - 1;
  106. // it must be a kernel
  107. if (!IsKernel(&drive, PRIMARY, index)) {
  108. Error("partition %d is not a ChromeOS kernel\n", params->set_partition);
  109. goto bad;
  110. }
  111. }
  112. // How many kernel partitions do I have?
  113. num_kernels = 0;
  114. for (i = 0; i < max_part; i++) {
  115. if (IsKernel(&drive, PRIMARY, i))
  116. num_kernels++;
  117. }
  118. if (num_kernels) {
  119. // Determine the current priority groups
  120. groups = NewGroupList(num_kernels);
  121. for (i = 0; i < max_part; i++) {
  122. if (!IsKernel(&drive, PRIMARY, i))
  123. continue;
  124. priority = GetPriority(&drive, PRIMARY, i);
  125. // Is this partition special?
  126. if (params->set_partition && (i+1 == params->set_partition)) {
  127. params->orig_priority = priority; // remember the original priority
  128. if (params->set_friends)
  129. AddToGroup(groups, priority, i); // we'll move them all later
  130. else
  131. AddToGroup(groups, 99, i); // move only this one
  132. } else {
  133. AddToGroup(groups, priority, i); // just remember
  134. }
  135. }
  136. // If we're including friends, then change the original group priority
  137. if (params->set_partition && params->set_friends) {
  138. ChangeGroup(groups, params->orig_priority, 99);
  139. }
  140. // Sorting gives the new order. Now we just need to reassign the
  141. // priorities.
  142. SortGroups(groups);
  143. // We'll never lower anything to zero, so if the last group is priority zero
  144. // we can ignore it.
  145. i = groups->num_groups;
  146. if (groups->group[i-1].priority == 0)
  147. groups->num_groups--;
  148. // Where do we start?
  149. if (params->max_priority)
  150. priority = params->max_priority;
  151. else
  152. priority = groups->num_groups > 15 ? 15 : groups->num_groups;
  153. // Figure out what the new values should be
  154. for (i=0; i<groups->num_groups; i++) {
  155. groups->group[i].priority = priority;
  156. if (priority > 1)
  157. priority--;
  158. }
  159. // Now apply the ranking to the GPT
  160. for (i=0; i<groups->num_groups; i++)
  161. for (j=0; j<groups->group[i].num_parts; j++)
  162. SetPriority(&drive, PRIMARY,
  163. groups->group[i].part[j], groups->group[i].priority);
  164. FreeGroups(groups);
  165. }
  166. // Write it all out
  167. UpdateAllEntries(&drive);
  168. return DriveClose(&drive, 1);
  169. bad:
  170. (void) DriveClose(&drive, 0);
  171. return CGPT_FAILED;
  172. }