1// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <getopt.h>
6#include <string.h>
7
8#include "cgpt.h"
9#include "vboot_host.h"
10
11extern const char* progname;
12
13static void Usage(void)
14{
15  printf("\nUsage: %s find [OPTIONS] [DRIVE]\n\n"
16         "Find a partition by its UUID or label. With no specified DRIVE\n"
17         "it scans all physical drives.\n\n"
18         "Options:\n"
19         "  -D NUM       Size (in bytes) of the disk where partitions reside\n"
20         "                 default 0, meaning partitions and GPT structs are\n"
21         "                 both on DRIVE\n"
22         "  -t GUID      Search for Partition Type GUID\n"
23         "  -u GUID      Search for Partition Unique ID\n"
24         "  -l LABEL     Search for Label\n"
25         "  -v           Be verbose in displaying matches (repeatable)\n"
26         "  -n           Numeric output only\n"
27         "  -1           Fail if more than one match is found\n"
28         "  -M FILE"
29         "      Matching partition data must also contain FILE content\n"
30         "  -O NUM"
31         "       Byte offset into partition to match content (default 0)\n"
32         "\n", progname);
33  PrintTypes();
34}
35
36// read a file into a buffer, return buffer and update size
37static uint8_t *ReadFile(const char *filename, uint64_t *size) {
38  FILE *f;
39  uint8_t *buf;
40
41  f = fopen(filename, "rb");
42  if (!f) {
43    return NULL;
44  }
45
46  fseek(f, 0, SEEK_END);
47  *size = ftell(f);
48  rewind(f);
49
50  buf = malloc(*size);
51  if (!buf) {
52    fclose(f);
53    return NULL;
54  }
55
56  if(1 != fread(buf, *size, 1, f)) {
57    fclose(f);
58    free(buf);
59    return NULL;
60  }
61
62  fclose(f);
63  return buf;
64}
65
66int cmd_find(int argc, char *argv[]) {
67
68  CgptFindParams params;
69  memset(&params, 0, sizeof(params));
70
71  int i;
72  int errorcnt = 0;
73  char *e = 0;
74  int c;
75
76  opterr = 0;                     // quiet, you
77  while ((c=getopt(argc, argv, ":hv1nt:u:l:M:O:D:")) != -1)
78  {
79    switch (c)
80    {
81    case 'D':
82      params.drive_size = strtoull(optarg, &e, 0);
83      if (!*optarg || (e && *e))
84      {
85        Error("invalid argument to -%c: \"%s\"\n", c, optarg);
86        errorcnt++;
87      }
88      break;
89    case 'v':
90      params.verbose++;
91      break;
92    case 'n':
93      params.numeric = 1;
94      break;
95    case '1':
96      params.oneonly = 1;
97      break;
98    case 'l':
99      params.set_label = 1;
100      params.label = optarg;
101      break;
102    case 't':
103      params.set_type = 1;
104      if (CGPT_OK != SupportedType(optarg, &params.type_guid) &&
105          CGPT_OK != StrToGuid(optarg, &params.type_guid)) {
106        Error("invalid argument to -%c: %s\n", c, optarg);
107        errorcnt++;
108      }
109      break;
110    case 'u':
111      params.set_unique = 1;
112      if (CGPT_OK != StrToGuid(optarg, &params.unique_guid)) {
113        Error("invalid argument to -%c: %s\n", c, optarg);
114        errorcnt++;
115      }
116      break;
117    case 'M':
118      params.matchbuf = ReadFile(optarg, &params.matchlen);
119      if (!params.matchbuf || !params.matchlen) {
120        Error("Unable to read from %s\n", optarg);
121        errorcnt++;
122      }
123      // Go ahead and allocate space for the comparison too
124      params.comparebuf = (uint8_t *)malloc(params.matchlen);
125      if (!params.comparebuf) {
126        Error("Unable to allocate %" PRIu64 "bytes for comparison buffer\n",
127              params.matchlen);
128        errorcnt++;
129      }
130      break;
131    case 'O':
132      params.matchoffset = strtoull(optarg, &e, 0);
133      if (!*optarg || (e && *e)) {
134        Error("invalid argument to -%c: \"%s\"\n", c, optarg);
135        errorcnt++;
136      }
137      break;
138
139    case 'h':
140      Usage();
141      return CGPT_OK;
142    case '?':
143      Error("unrecognized option: -%c\n", optopt);
144      errorcnt++;
145      break;
146    case ':':
147      Error("missing argument to -%c\n", optopt);
148      errorcnt++;
149      break;
150    default:
151      errorcnt++;
152      break;
153    }
154  }
155  if (!params.set_unique && !params.set_type && !params.set_label) {
156    Error("You must specify at least one of -t, -u, or -l\n");
157    errorcnt++;
158  }
159  if (errorcnt)
160  {
161    Usage();
162    return CGPT_FAILED;
163  }
164
165  if (optind < argc) {
166    for (i=optind; i<argc; i++) {
167      params.drive_name = argv[i];
168      CgptFind(&params);
169      }
170  } else {
171      CgptFind(&params);
172  }
173
174  if (params.oneonly && params.hits != 1) {
175    return CGPT_FAILED;
176  }
177
178  if (params.match_partnum) {
179    return CGPT_OK;
180  }
181
182  return CGPT_FAILED;
183}
184