summaryrefslogtreecommitdiff
path: root/cgpt
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2010-07-02 11:34:38 -0700
committerBill Richardson <wfrichar@chromium.org>2010-07-02 11:34:38 -0700
commit4a2093129f226b4b2b4684f2aebe2f4368f85fac (patch)
treed5e921c19b89cc5dfac01380351b616531fe14d8 /cgpt
parent5e9c0b94b1a10ceffb5e01de78210efd5dcfe581 (diff)
downloadvboot-4a2093129f226b4b2b4684f2aebe2f4368f85fac.tar.gz
Add 'find' command to cgpt, to search for partitions by UUID.
Review URL: http://codereview.chromium.org/2849040
Diffstat (limited to 'cgpt')
-rw-r--r--cgpt/Makefile1
-rw-r--r--cgpt/cgpt.c1
-rw-r--r--cgpt/cgpt.h1
-rw-r--r--cgpt/cmd_find.c275
4 files changed, 278 insertions, 0 deletions
diff --git a/cgpt/Makefile b/cgpt/Makefile
index e48708a3..3984628c 100644
--- a/cgpt/Makefile
+++ b/cgpt/Makefile
@@ -20,6 +20,7 @@ ALL_SRCS = \
cmd_create.c \
cmd_add.c \
cmd_boot.c \
+ cmd_find.c \
cgpt_common.c
main: $(PROGNAME)
diff --git a/cgpt/cgpt.c b/cgpt/cgpt.c
index d80bffea..d8604b1f 100644
--- a/cgpt/cgpt.c
+++ b/cgpt/cgpt.c
@@ -26,6 +26,7 @@ struct {
{"show", cmd_show, "Show partition table and entries"},
{"repair", cmd_repair, "Repair damaged GPT headers and tables"},
{"boot", cmd_boot, "Edit the PMBR sector for legacy BIOSes"},
+ {"find", cmd_find, "Locate a partition by its GUID"},
};
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index 504e6dd7..1ef74de3 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -122,6 +122,7 @@ int cmd_repair(int argc, char *argv[]);
int cmd_create(int argc, char *argv[]);
int cmd_add(int argc, char *argv[]);
int cmd_boot(int argc, char *argv[]);
+int cmd_find(int argc, char *argv[]);
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
const char *GptError(int errnum);
diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c
new file mode 100644
index 00000000..b50400e2
--- /dev/null
+++ b/cgpt/cmd_find.c
@@ -0,0 +1,275 @@
+// Copyright (c) 2010 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 <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+#include "cgptlib_internal.h"
+
+
+static void Usage(void)
+{
+ printf("\nUsage: %s find [OPTIONS] [DRIVE]\n\n"
+ "Find a partition by its UUID or label. With no specified DRIVE\n"
+ "it scans all physical drives.\n\n"
+ "Options:\n"
+ " -t GUID Search for Partition Type GUID\n"
+ " -u GUID Search for Partition Unique ID\n"
+ " -l LABEL Search for Label\n"
+ " -v Be verbose in displaying matches (repeatable)\n"
+ " -n Numeric output only\n"
+ " -1 Fail if more than one match is found\n"
+ "\n", progname);
+ PrintTypes();
+}
+
+
+// globals
+static int verbose = 0;
+static int set_unique = 0;
+static int set_type = 0;
+static int set_label = 0;
+static int oneonly = 0;
+static int numeric = 0;
+
+static Guid unique_guid;
+static Guid type_guid;
+static char *label;
+static int hits = 0;
+
+#define BUFSIZE 1024
+
+
+// remember one of the possibly many hits
+static int match_partnum = 0; // 0 for no match, 1-N for match
+static char match_filename[BUFSIZE]; // matching filename
+
+
+// FIXME: This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3
+static void showmatch(char *filename, int partnum, GptEntry *entry) {
+ printf("%s%d\n", filename, partnum);
+ if (verbose > 0)
+ EntryDetails(entry, partnum - 1, numeric);
+}
+
+// This returns true if a GPT partition matches the search criteria. If a match
+// isn't found (or if the file doesn't contain a GPT), it returns false. The
+// filename and partition number that matched is left in a global, since we
+// could have multiple hits.
+static int do_search(char *filename) {
+ int retval = 0;
+ int i;
+ struct drive drive;
+ GptEntry *entry;
+ char partlabel[sizeof(entry->name) * 3 / 2];
+
+ if (CGPT_OK != DriveOpen(filename, &drive))
+ return 0;
+
+ if (GPT_SUCCESS != GptSanityCheck(&drive.gpt)) {
+ (void) DriveClose(&drive, 0);
+ return 0;
+ }
+
+ for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
+ entry = GetEntry(&drive.gpt, PRIMARY, i);
+
+ if (IsZero(&entry->type))
+ continue;
+
+ int found = 0;
+ if ((set_unique && !memcmp(&unique_guid, &entry->unique, sizeof(Guid))) ||
+ (set_type && !memcmp(&type_guid, &entry->type, sizeof(Guid)))) {
+ found = 1;
+ } else if (set_label) {
+ UTF16ToUTF8(entry->name, (uint8_t *)partlabel);
+ if (!strncmp(label, partlabel, sizeof(partlabel))) {
+ found = 1;
+ }
+ }
+ if (found) {
+ hits++;
+ retval++;
+ showmatch(filename, i+1, entry);
+ if (!match_partnum) {
+ match_partnum = i+1;
+ strcpy(match_filename, filename);
+ }
+ }
+ }
+
+ (void) DriveClose(&drive, 0);
+
+ return retval;
+}
+
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEV_DIR "/dev"
+#define SYS_BLOCK_DIR "/sys/block"
+
+static const char *devdirs[] = { "/dev", "/devices", "/devfs", 0 };
+
+// Given basename "foo", see if we can find a whole, real device by that name.
+// This is copied from the logic in the linux utility 'findfs', although that
+// does more exhaustive searching.
+static char *is_wholedev(const char *basename) {
+ int i;
+ struct stat statbuf;
+ static char pathname[BUFSIZE]; // we'll return this.
+ char tmpname[BUFSIZE];
+
+// printf("basename is %s\n", basename);
+
+ // It should be a block device under /dev/,
+ for (i = 0; devdirs[i]; i++) {
+ sprintf(pathname, "%s/%s", devdirs[i], basename);
+// printf(" look at %s\n", pathname);
+
+ if (0 != stat(pathname, &statbuf))
+ continue;
+
+ if (!S_ISBLK(statbuf.st_mode))
+ continue;
+
+ // It should have a symlink called /sys/block/*/device
+ sprintf(tmpname, "%s/%s/device", SYS_BLOCK_DIR, basename);
+// printf(" look at %s\n", tmpname);
+
+ if (0 != lstat(tmpname, &statbuf))
+ continue;
+
+ if (!S_ISLNK(statbuf.st_mode))
+ continue;
+
+ // found it
+ return pathname;
+ }
+
+ return 0;
+}
+
+
+// This scans all the physical devices it can find, looking for a match. It
+// returns true if any matches were found, false otherwise.
+static int scan_real_devs(void) {
+ int found = 0;
+ char line[BUFSIZE];
+ char partname[128];
+ FILE *fp;
+ char *pathname;
+
+ fp = fopen(PROC_PARTITIONS, "r");
+ if (!fp) {
+ perror("can't read " PROC_PARTITIONS);
+ return found;
+ }
+
+ while (fgets(line, sizeof(line), fp)) {
+ int ma, mi;
+ long long unsigned int sz;
+
+ if (sscanf(line, " %d %d %llu %128[^\n ]", &ma, &mi, &sz, partname) != 4)
+ continue;
+
+ if ((pathname = is_wholedev(partname))) {
+ if (do_search(pathname)) {
+ found++;
+ }
+ }
+ }
+
+ fclose(fp);
+ return found;
+}
+
+
+int cmd_find(int argc, char *argv[]) {
+ int i;
+
+ int errorcnt = 0;
+ int c;
+
+ opterr = 0; // quiet, you
+ while ((c=getopt(argc, argv, ":hv1nt:u:l:")) != -1)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose++;
+ break;
+ case 'n':
+ numeric = 1;
+ break;
+ case '1':
+ oneonly = 1;
+ break;
+ case 'l':
+ set_label = 1;
+ label = optarg;
+ break;
+ case 't':
+ set_type = 1;
+ if (CGPT_OK != SupportedType(optarg, &type_guid) &&
+ CGPT_OK != StrToGuid(optarg, &type_guid)) {
+ Error("invalid argument to -%c: %s\n", c, optarg);
+ errorcnt++;
+ }
+ break;
+ case 'u':
+ set_unique = 1;
+ if (CGPT_OK != StrToGuid(optarg, &unique_guid)) {
+ Error("invalid argument to -%c: %s\n", c, optarg);
+ errorcnt++;
+ }
+ break;
+
+ case 'h':
+ Usage();
+ return CGPT_OK;
+ case '?':
+ Error("unrecognized option: -%c\n", optopt);
+ errorcnt++;
+ break;
+ case ':':
+ Error("missing argument to -%c\n", optopt);
+ errorcnt++;
+ break;
+ default:
+ errorcnt++;
+ break;
+ }
+ }
+ if (errorcnt)
+ {
+ Usage();
+ return CGPT_FAILED;
+ }
+
+
+ if (optind < argc) {
+ for (i=optind; i<argc; i++)
+ do_search(argv[i]);
+ } else {
+ scan_real_devs();
+ }
+
+ if (oneonly && hits != 1) {
+ return CGPT_FAILED;
+ }
+
+ if (match_partnum) {
+ return CGPT_OK;
+ }
+
+ return CGPT_FAILED;
+}