diff options
author | Bill Richardson <wfrichar@chromium.org> | 2010-07-02 11:34:38 -0700 |
---|---|---|
committer | Bill Richardson <wfrichar@chromium.org> | 2010-07-02 11:34:38 -0700 |
commit | 4a2093129f226b4b2b4684f2aebe2f4368f85fac (patch) | |
tree | d5e921c19b89cc5dfac01380351b616531fe14d8 /cgpt | |
parent | 5e9c0b94b1a10ceffb5e01de78210efd5dcfe581 (diff) | |
download | vboot-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/Makefile | 1 | ||||
-rw-r--r-- | cgpt/cgpt.c | 1 | ||||
-rw-r--r-- | cgpt/cgpt.h | 1 | ||||
-rw-r--r-- | cgpt/cmd_find.c | 275 |
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; +} |