diff options
Diffstat (limited to 'cgpt/cmd_find.c')
-rw-r--r-- | cgpt/cmd_find.c | 283 |
1 files changed, 29 insertions, 254 deletions
diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c index 7a0523ff..9b945465 100644 --- a/cgpt/cmd_find.c +++ b/cgpt/cmd_find.c @@ -1,20 +1,13 @@ -// 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 <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <uuid/uuid.h> - -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -36,34 +29,6 @@ static void Usage(void) 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 uint8_t *matchbuf = NULL; -static uint64_t matchlen = 0; -static uint64_t matchoffset = 0; -static uint8_t *comparebuf = NULL; - -static Guid unique_guid; -static Guid type_guid; -static char *label; -static int hits = 0; - -#define BUFSIZE 1024 -// FIXME: currently we only support 512-byte sectors. -#define LBA_SIZE 512 - - -// 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 - - // read a file into a buffer, return buffer and update size static uint8_t *ReadFile(const char *filename, uint64_t *size) { FILE *f; @@ -94,203 +59,11 @@ static uint8_t *ReadFile(const char *filename, uint64_t *size) { return buf; } -// fill comparebuf with the data to be examined, returning true on success. -static int FillBuffer(int fd, uint64_t pos, uint64_t count) { - uint8_t *bufptr = comparebuf; - - if (-1 == lseek(fd, pos, SEEK_SET)) - return 0; - - // keep reading until done or error - while (count) { - ssize_t bytes_read = read(fd, bufptr, count); - // negative means error, 0 means (unexpected) EOF - if (bytes_read <= 0) - return 0; - count -= bytes_read; - bufptr += bytes_read; - } - - return 1; -} - -// check partition data content. return true for match, 0 for no match or error -static int match_content(struct drive *drive, GptEntry *entry) { - uint64_t part_size; - - if (!matchlen) - return 1; - - // Ensure that the region we want to match against is inside the partition. - part_size = LBA_SIZE * (entry->ending_lba - entry->starting_lba + 1); - if (matchoffset + matchlen > part_size) { - return 0; - } - - // Read the partition data. - if (!FillBuffer(drive->fd, - (LBA_SIZE * entry->starting_lba) + matchoffset, - matchlen)) { - Error("unable to read partition data\n"); - return 0; - } - - // Compare it - if (0 == memcmp(matchbuf, comparebuf, matchlen)) { - return 1; - } - - // Nope. - return 0; -} - -// This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3, /dev/sda -> /dev/sda3 -static void showmatch(char *filename, int partnum, GptEntry *entry) { - char * format = "%s%d\n"; - if (strncmp("/dev/mmcblk", filename, 11) == 0) - format = "%sp%d\n"; - if (numeric) - printf("%d\n", partnum); - else - printf(format, 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[GPT_PARTNAME_LEN]; - - 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, ANY_VALID, i); - - if (IsZero(&entry->type)) - continue; - - int found = 0; - if ((set_unique && GuidEqual(&unique_guid, &entry->unique)) || - (set_type && GuidEqual(&type_guid, &entry->type))) { - found = 1; - } else if (set_label) { - if (CGPT_OK != UTF16ToUTF8(entry->name, - sizeof(entry->name) / sizeof(entry->name[0]), - (uint8_t *)partlabel, sizeof(partlabel))) { - Error("The label cannot be converted from UTF16, so abort.\n"); - return 0; - } - if (!strncmp(label, partlabel, sizeof(partlabel))) { - found = 1; - } - } - if (found && match_content(&drive, entry)) { - 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]; - - // It should be a block device under /dev/, - for (i = 0; devdirs[i]; i++) { - sprintf(pathname, "%s/%s", devdirs[i], basename); - - 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); - - 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]; // max size for /proc/partition lines? - 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 %127[^\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[]) { + CgptFindParams params; + memset(¶ms, 0, sizeof(params)); -int cmd_find(int argc, char *argv[]) { int i; int errorcnt = 0; char *e = 0; @@ -302,49 +75,49 @@ int cmd_find(int argc, char *argv[]) { switch (c) { case 'v': - verbose++; + params.verbose++; break; case 'n': - numeric = 1; + params.numeric = 1; break; case '1': - oneonly = 1; + params.oneonly = 1; break; case 'l': - set_label = 1; - label = optarg; + params.set_label = 1; + params.label = optarg; break; case 't': - set_type = 1; - if (CGPT_OK != SupportedType(optarg, &type_guid) && - CGPT_OK != StrToGuid(optarg, &type_guid)) { + params.set_type = 1; + if (CGPT_OK != SupportedType(optarg, ¶ms.type_guid) && + CGPT_OK != StrToGuid(optarg, ¶ms.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)) { + params.set_unique = 1; + if (CGPT_OK != StrToGuid(optarg, ¶ms.unique_guid)) { Error("invalid argument to -%c: %s\n", c, optarg); errorcnt++; } break; case 'M': - matchbuf = ReadFile(optarg, &matchlen); - if (!matchbuf || !matchlen) { + params.matchbuf = ReadFile(optarg, ¶ms.matchlen); + if (!params.matchbuf || !params.matchlen) { Error("Unable to read from %s\n", optarg); errorcnt++; } // Go ahead and allocate space for the comparison too - comparebuf = (uint8_t *)malloc(matchlen); - if (!comparebuf) { + params.comparebuf = (uint8_t *)malloc(params.matchlen); + if (!params.comparebuf) { Error("Unable to allocate %" PRIu64 "bytes for comparison buffer\n", - matchlen); + params.matchlen); errorcnt++; } break; case 'O': - matchoffset = strtoull(optarg, &e, 0); + params.matchoffset = strtoull(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); errorcnt++; @@ -367,7 +140,7 @@ int cmd_find(int argc, char *argv[]) { break; } } - if (!set_unique && !set_type && !set_label) { + if (!params.set_unique && !params.set_type && !params.set_label) { Error("You must specify at least one of -t, -u, or -l\n"); errorcnt++; } @@ -378,17 +151,19 @@ int cmd_find(int argc, char *argv[]) { } if (optind < argc) { - for (i=optind; i<argc; i++) - do_search(argv[i]); + for (i=optind; i<argc; i++) { + params.driveName = argv[i]; + cgpt_find(¶ms); + } } else { - scan_real_devs(); + cgpt_find(¶ms); } - if (oneonly && hits != 1) { + if (params.oneonly && params.hits != 1) { return CGPT_FAILED; } - if (match_partnum) { + if (params.match_partnum) { return CGPT_OK; } |