| Index: cgpt/cmd_find.c
|
| diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b50400e25cadfb583d0ec113b9b8c9deb1281be0
|
| --- /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;
|
| +}
|
|
|