Refactor of cgpt tool for 32->64 autoupdate work.

This check-in splits the cgpt into two layers. The top layer (cmd_* files) does
the command-line parsing and the bottom layer (cgpt_* files) does the actual
cgpt work.

This is done so that the bottom layer can be reused for the monolithic
C++ post-installer code that will be done in subsequent checkins.

BUG=chromium-os:25374
TEST=Tested with existing cgpt unit tests as well as running the cgpt commands manually.

Change-Id: I69a31eb3e867a1430cac9a694581331368aa7bb4
Reviewed-on: https://gerrit.chromium.org/gerrit/14940
Reviewed-by: Jay Srinivasan <jaysri@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
Commit-Ready: Jay Srinivasan <jaysri@chromium.org>
diff --git a/cgpt/cmd_prioritize.c b/cgpt/cmd_prioritize.c
index 3f34568..cb655f2 100644
--- a/cgpt/cmd_prioritize.c
+++ b/cgpt/cmd_prioritize.c
@@ -1,16 +1,14 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cgpt.h"
-
 #include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <uuid/uuid.h>
 
-#include "cgptlib_internal.h"
+#include "cgpt_params.h"
 
 static void Usage(void)
 {
@@ -33,107 +31,12 @@
          "\n", progname);
 }
 
-//////////////////////////////////////////////////////////////////////////////
-// I want a sorted list of priority groups, where each element in the list
-// contains an unordered list of GPT partition numbers. This is a stupid
-// implementation, but our needs are simple and don't justify the time or space
-// it would take to write a "better" one.
-#define MAX_GROUPS 17                   // 0-15, plus one "higher"
-
-typedef struct {
-  int priority;                         // priority of this group
-  int num_parts;                        // number of partitions in this group
-  uint32_t *part;                       // array of partitions in this group
-} group_t;
-
-typedef struct {
-  int max_parts;                       // max number of partitions in any group
-  int num_groups;                      // number of non-empty groups
-  group_t group[MAX_GROUPS];           // array of groups
-} group_list_t;
-
-
-static group_list_t *NewGroupList(int max_p) {
-  int i;
-  group_list_t *gl = (group_list_t *)malloc(sizeof(group_list_t));
-  require(gl);
-  gl->max_parts = max_p;
-  gl->num_groups = 0;
-  // reserve space for the maximum number of partitions in every group
-  for (i=0; i<MAX_GROUPS; i++) {
-    gl->group[i].priority = -1;
-    gl->group[i].num_parts = 0;
-    gl->group[i].part = (uint32_t *)malloc(sizeof(uint32_t) * max_p);
-    require(gl->group[i].part);
-  }
-
-  return gl;
-}
-
-static void FreeGroups(group_list_t *gl) {
-  int i;
-  for (i=0; i<MAX_GROUPS; i++)
-    free(gl->group[i].part);
-  free(gl);
-}
-
-static void AddToGroup(group_list_t *gl, int priority, int partition) {
-  int i;
-  // See if I've already got a group with this priority
-  for (i=0; i<gl->num_groups; i++)
-    if (gl->group[i].priority == priority)
-      break;
-  if (i == gl->num_groups) {
-    // no, add a group
-    require(i < MAX_GROUPS);
-    gl->num_groups++;
-    gl->group[i].priority = priority;
-  }
-  // add the partition to it
-  int j = gl->group[i].num_parts;
-  gl->group[i].part[j] = partition;
-  gl->group[i].num_parts++;
-}
-
-static void ChangeGroup(group_list_t *gl, int old_priority, int new_priority) {
-  int i;
-  for (i=0; i<gl->num_groups; i++)
-    if (gl->group[i].priority == old_priority) {
-      gl->group[i].priority = new_priority;
-      break;
-    }
-}
-
-static void SortGroups(group_list_t *gl) {
-  int i, j;
-  group_t tmp;
-
-  // straight insertion sort is fast enough
-  for (i=1; i<gl->num_groups; i++) {
-    tmp = gl->group[i];
-    for (j=i; j && (gl->group[j-1].priority < tmp.priority); j--)
-      gl->group[j] = gl->group[j-1];
-    gl->group[j] = tmp;
-  }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
 int cmd_prioritize(int argc, char *argv[]) {
   struct drive drive;
-  uint32_t set_partition = 0;
-  int set_friends = 0;
-  int max_priority = 0;
-  int priority;
-  int orig_priority = 0;
-  int gpt_retval;
-  GptEntry *entry;
-  uint32_t index;
-  uint32_t max_part;
-  int num_kernels;
-  int i,j;
-  group_list_t *groups;
+
+  CgptPrioritizeParams params;
+  memset(&params, 0, sizeof(params));
+
 
   int c;
   int errorcnt = 0;
@@ -145,7 +48,7 @@
     switch (c)
     {
     case 'i':
-      set_partition = (uint32_t)strtoul(optarg, &e, 0);
+      params.set_partition = (uint32_t)strtoul(optarg, &e, 0);
       if (!*optarg || (e && *e))
       {
         Error("invalid argument to -%c: \"%s\"\n", c, optarg);
@@ -153,16 +56,16 @@
       }
       break;
     case 'f':
-      set_friends = 1;
+      params.set_friends = 1;
       break;
     case 'P':
-      max_priority = (int)strtol(optarg, &e, 0);
+      params.max_priority = (int)strtol(optarg, &e, 0);
       if (!*optarg || (e && *e))
       {
         Error("invalid argument to -%c: \"%s\"\n", c, optarg);
         errorcnt++;
       }
-      if (max_priority < 1 || max_priority > 15) {
+      if (params.max_priority < 1 || params.max_priority > 15) {
         Error("value for -%c must be between 1 and 15\n", c);
         errorcnt++;
       }
@@ -190,7 +93,7 @@
     return CGPT_FAILED;
   }
 
-  if (set_friends && !set_partition) {
+  if (params.set_friends && !params.set_partition) {
     Error("the -f option is only useful with the -i option\n");
     Usage();
     return CGPT_FAILED;
@@ -201,114 +104,7 @@
     return CGPT_FAILED;
   }
 
-  if (CGPT_OK != DriveOpen(argv[optind], &drive))
-    return CGPT_FAILED;
+  params.driveName = argv[optind];
 
-  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
-    Error("GptSanityCheck() returned %d: %s\n",
-          gpt_retval, GptError(gpt_retval));
-    return CGPT_FAILED;
-  }
-
-  max_part = GetNumberOfEntries(&drive.gpt);
-
-  if (set_partition) {
-    if (set_partition < 1 || set_partition > max_part) {
-      Error("invalid partition number: %d (must be between 1 and %d\n",
-            set_partition, max_part);
-      goto bad;
-    }
-    index = set_partition - 1;
-    // it must be a kernel
-    entry = GetEntry(&drive.gpt, PRIMARY, index);
-    if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) {
-      Error("partition %d is not a ChromeOS kernel\n", set_partition);
-      goto bad;
-    }
-  }
-
-  // How many kernel partitions do I have?
-  num_kernels = 0;
-  for (i = 0; i < max_part; i++) {
-    entry = GetEntry(&drive.gpt, PRIMARY, i);
-    if (GuidEqual(&entry->type, &guid_chromeos_kernel))
-      num_kernels++;
-  }
-
-  if (!num_kernels)
-    // nothing to do, so don't
-    goto good;
-
-  // Determine the current priority groups
-  groups = NewGroupList(num_kernels);
-  for (i = 0; i < max_part; i++) {
-    entry = GetEntry(&drive.gpt, PRIMARY, i);
-    if (!GuidEqual(&entry->type, &guid_chromeos_kernel))
-      continue;
-
-    priority = GetPriority(&drive.gpt, PRIMARY, i);
-
-    // Is this partition special?
-    if (set_partition && (i+1 == set_partition)) {
-      orig_priority = priority;         // remember the original priority
-      if (set_friends)
-        AddToGroup(groups, priority, i); // we'll move them all later
-      else
-        AddToGroup(groups, 99, i);      // move only this one
-    } else {
-      AddToGroup(groups, priority, i);  // just remember
-    }
-  }
-
-  // If we're including friends, then change the original group priority
-  if (set_partition && set_friends) {
-    ChangeGroup(groups, orig_priority, 99);
-  }
-
-  // Sorting gives the new order. Now we just need to reassign the
-  // priorities.
-  SortGroups(groups);
-
-  // We'll never lower anything to zero, so if the last group is priority zero
-  // we can ignore it.
-  i = groups->num_groups;
-  if (groups->group[i-1].priority == 0)
-    groups->num_groups--;
-
-  // Where do we start?
-  if (max_priority)
-    priority = max_priority;
-  else
-    priority = groups->num_groups > 15 ? 15 : groups->num_groups;
-
-  // Figure out what the new values should be
-  for (i=0; i<groups->num_groups; i++) {
-    groups->group[i].priority = priority;
-    if (priority > 1)
-      priority--;
-  }
-
-  // Now apply the ranking to the GPT
-  for (i=0; i<groups->num_groups; i++)
-    for (j=0; j<groups->group[i].num_parts; j++)
-      SetPriority(&drive.gpt, PRIMARY,
-                  groups->group[i].part[j], groups->group[i].priority);
-
-  FreeGroups(groups);
-
-
-  // Write it all out
-good:
-  RepairEntries(&drive.gpt, MASK_PRIMARY);
-  RepairHeader(&drive.gpt, MASK_PRIMARY);
-
-  drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
-                         GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
-  UpdateCrc(&drive.gpt);
-
-  return DriveClose(&drive, 1);
-
-bad:
-  (void) DriveClose(&drive, 0);
-  return CGPT_FAILED;
+  return cgpt_prioritize(&params);
 }