OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 |
| 5 #include "cgpt.h" |
| 6 |
| 7 #include <getopt.h> |
| 8 #include <stdio.h> |
| 9 #include <stdlib.h> |
| 10 #include <string.h> |
| 11 #include <uuid/uuid.h> |
| 12 |
| 13 #include "cgptlib_internal.h" |
| 14 |
| 15 static void Usage(void) |
| 16 { |
| 17 printf("\nUsage: %s prioritize [OPTIONS] DRIVE\n\n" |
| 18 "Reorder the priority of all active ChromeOS Kernel partitions.\n\n" |
| 19 "Options:\n" |
| 20 " -P NUM Highest priority to use in the new ordering. The\n" |
| 21 " other partitions will be ranked in decreasing\n" |
| 22 " priority while preserving their original order.\n" |
| 23 " If necessary the lowest ranks will be coalesced.\n" |
| 24 " No active kernels will be lowered to priority 0.\n" |
| 25 " -i NUM Specify the partition to make the highest in the new\n" |
| 26 " order.\n" |
| 27 " -f Friends of the given partition (those with the same\n" |
| 28 " starting priority) are also updated to the new\n" |
| 29 " highest priority.\n" |
| 30 "\n" |
| 31 "With no options this will set the lowest active kernel to\n" |
| 32 "priority 1 while maintaining the original order.\n" |
| 33 "\n", progname); |
| 34 } |
| 35 |
| 36 ////////////////////////////////////////////////////////////////////////////// |
| 37 // I want a sorted list of priority groups, where each element in the list |
| 38 // contains an unordered list of GPT partition numbers. This is a stupid |
| 39 // implementation, but our needs are simple and don't justify the time or space |
| 40 // it would take to write a "better" one. |
| 41 #define MAX_GROUPS 17 // 0-15, plus one "higher" |
| 42 |
| 43 typedef struct { |
| 44 int priority; // priority of this group |
| 45 int num_parts; // number of partitions in this group |
| 46 uint32_t *part; // array of partitions in this group |
| 47 } group_t; |
| 48 |
| 49 typedef struct { |
| 50 int max_parts; // max number of partitions in any group |
| 51 int num_groups; // number of non-empty groups |
| 52 group_t group[MAX_GROUPS]; // array of groups |
| 53 } group_list_t; |
| 54 |
| 55 |
| 56 static group_list_t *NewGroupList(int max_p) { |
| 57 int i; |
| 58 group_list_t *gl = (group_list_t *)malloc(sizeof(group_list_t)); |
| 59 require(gl); |
| 60 gl->max_parts = max_p; |
| 61 gl->num_groups = 0; |
| 62 // reserve space for the maximum number of partitions in every group |
| 63 for (i=0; i<MAX_GROUPS; i++) { |
| 64 gl->group[i].priority = -1; |
| 65 gl->group[i].num_parts = 0; |
| 66 gl->group[i].part = (uint32_t *)malloc(sizeof(uint32_t) * max_p); |
| 67 require(gl->group[i].part); |
| 68 } |
| 69 |
| 70 return gl; |
| 71 } |
| 72 |
| 73 static void FreeGroups(group_list_t *gl) { |
| 74 int i; |
| 75 for (i=0; i<MAX_GROUPS; i++) |
| 76 free(gl->group[i].part); |
| 77 free(gl); |
| 78 } |
| 79 |
| 80 static void AddToGroup(group_list_t *gl, int priority, int partition) { |
| 81 int i; |
| 82 // See if I've already got a group with this priority |
| 83 for (i=0; i<gl->num_groups; i++) |
| 84 if (gl->group[i].priority == priority) |
| 85 break; |
| 86 if (i == gl->num_groups) { |
| 87 // no, add a group |
| 88 require(i < MAX_GROUPS); |
| 89 gl->num_groups++; |
| 90 gl->group[i].priority = priority; |
| 91 } |
| 92 // add the partition to it |
| 93 int j = gl->group[i].num_parts; |
| 94 gl->group[i].part[j] = partition; |
| 95 gl->group[i].num_parts++; |
| 96 } |
| 97 |
| 98 static void ChangeGroup(group_list_t *gl, int old_priority, int new_priority) { |
| 99 int i; |
| 100 for (i=0; i<gl->num_groups; i++) |
| 101 if (gl->group[i].priority == old_priority) { |
| 102 gl->group[i].priority = new_priority; |
| 103 break; |
| 104 } |
| 105 } |
| 106 |
| 107 static void SortGroups(group_list_t *gl) { |
| 108 int i, j; |
| 109 group_t tmp; |
| 110 |
| 111 // straight insertion sort is fast enough |
| 112 for (i=1; i<gl->num_groups; i++) { |
| 113 tmp = gl->group[i]; |
| 114 for (j=i; j && (gl->group[j-1].priority < tmp.priority); j--) |
| 115 gl->group[j] = gl->group[j-1]; |
| 116 gl->group[j] = tmp; |
| 117 } |
| 118 } |
| 119 |
| 120 |
| 121 ////////////////////////////////////////////////////////////////////////////// |
| 122 |
| 123 int cmd_prioritize(int argc, char *argv[]) { |
| 124 struct drive drive; |
| 125 uint32_t set_partition = 0; |
| 126 int set_friends = 0; |
| 127 int max_priority = 0; |
| 128 int priority; |
| 129 int orig_priority = 0; |
| 130 int gpt_retval; |
| 131 GptEntry *entry; |
| 132 uint32_t index; |
| 133 uint32_t max_part; |
| 134 int num_kernels; |
| 135 int i,j; |
| 136 group_list_t *groups; |
| 137 |
| 138 int c; |
| 139 int errorcnt = 0; |
| 140 char *e = 0; |
| 141 |
| 142 opterr = 0; // quiet, you |
| 143 while ((c=getopt(argc, argv, ":hi:fP:")) != -1) |
| 144 { |
| 145 switch (c) |
| 146 { |
| 147 case 'i': |
| 148 set_partition = (uint32_t)strtoul(optarg, &e, 0); |
| 149 if (!*optarg || (e && *e)) |
| 150 { |
| 151 Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 152 errorcnt++; |
| 153 } |
| 154 break; |
| 155 case 'f': |
| 156 set_friends = 1; |
| 157 break; |
| 158 case 'P': |
| 159 max_priority = (int)strtol(optarg, &e, 0); |
| 160 if (!*optarg || (e && *e)) |
| 161 { |
| 162 Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 163 errorcnt++; |
| 164 } |
| 165 if (max_priority < 1 || max_priority > 15) { |
| 166 Error("value for -%c must be between 1 and 15\n", c); |
| 167 errorcnt++; |
| 168 } |
| 169 break; |
| 170 |
| 171 case 'h': |
| 172 Usage(); |
| 173 return CGPT_OK; |
| 174 case '?': |
| 175 Error("unrecognized option: -%c\n", optopt); |
| 176 errorcnt++; |
| 177 break; |
| 178 case ':': |
| 179 Error("missing argument to -%c\n", optopt); |
| 180 errorcnt++; |
| 181 break; |
| 182 default: |
| 183 errorcnt++; |
| 184 break; |
| 185 } |
| 186 } |
| 187 if (errorcnt) |
| 188 { |
| 189 Usage(); |
| 190 return CGPT_FAILED; |
| 191 } |
| 192 |
| 193 if (set_friends && !set_partition) { |
| 194 Error("the -f option is only useful with the -i option\n"); |
| 195 Usage(); |
| 196 return CGPT_FAILED; |
| 197 } |
| 198 |
| 199 if (optind >= argc) { |
| 200 Error("missing drive argument\n"); |
| 201 return CGPT_FAILED; |
| 202 } |
| 203 |
| 204 if (CGPT_OK != DriveOpen(argv[optind], &drive)) |
| 205 return CGPT_FAILED; |
| 206 |
| 207 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { |
| 208 Error("GptSanityCheck() returned %d: %s\n", |
| 209 gpt_retval, GptError(gpt_retval)); |
| 210 return CGPT_FAILED; |
| 211 } |
| 212 |
| 213 max_part = GetNumberOfEntries(&drive.gpt); |
| 214 |
| 215 if (set_partition) { |
| 216 if (set_partition < 1 || set_partition > max_part) { |
| 217 Error("invalid partition number: %d (must be between 1 and %d\n", |
| 218 set_partition, max_part); |
| 219 goto bad; |
| 220 } |
| 221 index = set_partition - 1; |
| 222 // it must be a kernel |
| 223 entry = GetEntry(&drive.gpt, PRIMARY, index); |
| 224 if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) { |
| 225 Error("partition %d is not a ChromeOS kernel\n", set_partition); |
| 226 goto bad; |
| 227 } |
| 228 } |
| 229 |
| 230 // How many kernel partitions do I have? |
| 231 num_kernels = 0; |
| 232 for (i = 0; i < max_part; i++) { |
| 233 entry = GetEntry(&drive.gpt, PRIMARY, i); |
| 234 if (GuidEqual(&entry->type, &guid_chromeos_kernel)) |
| 235 num_kernels++; |
| 236 } |
| 237 |
| 238 if (!num_kernels) |
| 239 // nothing to do, so don't |
| 240 goto good; |
| 241 |
| 242 // Determine the current priority groups |
| 243 groups = NewGroupList(num_kernels); |
| 244 for (i = 0; i < max_part; i++) { |
| 245 entry = GetEntry(&drive.gpt, PRIMARY, i); |
| 246 if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) |
| 247 continue; |
| 248 |
| 249 priority = GetPriority(&drive.gpt, PRIMARY, i); |
| 250 |
| 251 // Is this partition special? |
| 252 if (set_partition && (i+1 == set_partition)) { |
| 253 orig_priority = priority; // remember the original priority |
| 254 if (set_friends) |
| 255 AddToGroup(groups, priority, i); // we'll move them all later |
| 256 else |
| 257 AddToGroup(groups, 99, i); // move only this one |
| 258 } else { |
| 259 AddToGroup(groups, priority, i); // just remember |
| 260 } |
| 261 } |
| 262 |
| 263 // If we're including friends, then change the original group priority |
| 264 if (set_partition && set_friends) { |
| 265 ChangeGroup(groups, orig_priority, 99); |
| 266 } |
| 267 |
| 268 // Sorting gives the new order. Now we just need to reassign the |
| 269 // priorities. |
| 270 SortGroups(groups); |
| 271 |
| 272 // We'll never lower anything to zero, so if the last group is priority zero |
| 273 // we can ignore it. |
| 274 i = groups->num_groups; |
| 275 if (groups->group[i-1].priority == 0) |
| 276 groups->num_groups--; |
| 277 |
| 278 // Where do we start? |
| 279 if (max_priority) |
| 280 priority = max_priority; |
| 281 else |
| 282 priority = groups->num_groups > 15 ? 15 : groups->num_groups; |
| 283 |
| 284 // Figure out what the new values should be |
| 285 for (i=0; i<groups->num_groups; i++) { |
| 286 groups->group[i].priority = priority; |
| 287 if (priority > 1) |
| 288 priority--; |
| 289 } |
| 290 |
| 291 // Now apply the ranking to the GPT |
| 292 for (i=0; i<groups->num_groups; i++) |
| 293 for (j=0; j<groups->group[i].num_parts; j++) |
| 294 SetPriority(&drive.gpt, PRIMARY, |
| 295 groups->group[i].part[j], groups->group[i].priority); |
| 296 |
| 297 FreeGroups(groups); |
| 298 |
| 299 |
| 300 // Write it all out |
| 301 good: |
| 302 RepairEntries(&drive.gpt, MASK_PRIMARY); |
| 303 RepairHeader(&drive.gpt, MASK_PRIMARY); |
| 304 |
| 305 drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | |
| 306 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); |
| 307 UpdateCrc(&drive.gpt); |
| 308 |
| 309 return DriveClose(&drive, 1); |
| 310 |
| 311 bad: |
| 312 (void) DriveClose(&drive, 0); |
| 313 return CGPT_FAILED; |
| 314 } |
OLD | NEW |