1 /*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <getopt.h>
9 #include <inttypes.h>
10 #include <limits.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 #include "fmap.h"
21 #include "futility.h"
22
23
24 static const char usage[] = "\n"
25 "Usage: " MYNAME " %s [OPTIONS] FILE AREA:file [AREA:file ...]\n"
26 "\n"
27 "Replace the contents of specific FMAP areas. This is the complement\n"
28 "of " MYNAME " dump_fmap -x FILE AREA [AREA ...]\n"
29 "\n"
30 "Options:\n"
31 " -o OUTFILE Write the result to this file, instead of modifying\n"
32 " the input file. This is safer, since there are no\n"
33 " safeguards against doing something stupid.\n"
34 "\n"
35 "Example:\n"
36 "\n"
37 " This will clear the RO_VPD area, and scramble VBLOCK_B:\n"
38 "\n"
39 " " MYNAME " %s bios.bin RO_VPD:/dev/zero VBLOCK_B:/dev/urandom\n"
40 "\n";
41
help_and_quit(const char * prog)42 static void help_and_quit(const char *prog)
43 {
44 printf(usage, prog, prog);
45 }
46
47 static const struct option long_opts[] = {
48 /* name hasarg *flag val */
49 {NULL, 0, NULL, 0},
50 };
51 static char *short_opts = ":o:";
52
53
copy_to_area(char * file,uint8_t * buf,uint32_t len,char * area)54 static int copy_to_area(char *file, uint8_t *buf, uint32_t len, char *area)
55 {
56 FILE *fp;
57 int retval = 0;
58 int n;
59
60 fp = fopen(file, "r");
61 if (!fp) {
62 fprintf(stderr, "area %s: can't open %s for reading: %s\n",
63 area, file, strerror(errno));
64 return 1;
65 }
66
67 n = fread(buf, 1, len, fp);
68 if (n == 0) {
69 if (feof(fp))
70 fprintf(stderr, "area %s: unexpected EOF on %s\n",
71 area, file);
72 if (ferror(fp))
73 fprintf(stderr, "area %s: can't read from %s: %s\n",
74 area, file, strerror(errno));
75 retval = 1;
76 } else if (n < len) {
77 fprintf(stderr, "Warning on area %s: only read %d "
78 "(not %d) from %s\n", area, n, len, file);
79 }
80
81 if (0 != fclose(fp)) {
82 fprintf(stderr, "area %s: error closing %s: %s\n",
83 area, file, strerror(errno));
84 retval = 1;
85 }
86
87 return retval;
88 }
89
90
do_load_fmap(int argc,char * argv[])91 static int do_load_fmap(int argc, char *argv[])
92 {
93 char *infile = 0;
94 char *outfile = 0;
95 uint8_t *buf;
96 uint32_t len;
97 FmapHeader *fmap;
98 FmapAreaHeader *ah;
99 int errorcnt = 0;
100 int fd, i;
101
102 opterr = 0; /* quiet, you */
103 while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
104 switch (i) {
105 case 'o':
106 outfile = optarg;
107 break;
108 case '?':
109 if (optopt)
110 fprintf(stderr, "Unrecognized option: -%c\n",
111 optopt);
112 else
113 fprintf(stderr, "Unrecognized option\n");
114 errorcnt++;
115 break;
116 case ':':
117 fprintf(stderr, "Missing argument to -%c\n", optopt);
118 errorcnt++;
119 break;
120 default:
121 DIE;
122 }
123 }
124
125 if (errorcnt) {
126 help_and_quit(argv[0]);
127 return 1;
128 }
129
130 if (argc - optind < 2) {
131 fprintf(stderr,
132 "You must specify an input file"
133 " and at least one AREA:file argument\n");
134 help_and_quit(argv[0]);
135 return 1;
136 }
137
138 infile = argv[optind++];
139
140 /* okay, let's do it ... */
141 if (outfile)
142 futil_copy_file_or_die(infile, outfile);
143 else
144 outfile = infile;
145
146 fd = open(outfile, O_RDWR);
147 if (fd < 0) {
148 fprintf(stderr, "Can't open %s: %s\n",
149 outfile, strerror(errno));
150 return 1;
151 }
152
153 errorcnt |= futil_map_file(fd, MAP_RW, &buf, &len);
154 if (errorcnt)
155 goto done_file;
156
157 fmap = fmap_find(buf, len);
158 if (!fmap) {
159 fprintf(stderr, "Can't find an FMAP in %s\n", infile);
160 errorcnt++;
161 goto done_map;
162 }
163
164 for (i = optind; i < argc; i++) {
165 char *a = argv[i];
166 char *f = strchr(a, ':');
167
168 if (!f || a == f || *(f+1) == '\0') {
169 fprintf(stderr, "argument \"%s\" is bogus\n", a);
170 errorcnt++;
171 break;
172 }
173 *f++ = '\0';
174 uint8_t *area_buf = fmap_find_by_name(buf, len, fmap, a, &ah);
175 if (!area_buf) {
176 fprintf(stderr, "Can't find area \"%s\" in FMAP\n", a);
177 errorcnt++;
178 break;
179 }
180
181 if (0 != copy_to_area(f, area_buf, ah->area_size, a)) {
182 errorcnt++;
183 break;
184 }
185 }
186
187 done_map:
188 errorcnt |= futil_unmap_file(fd, 1, buf, len);
189
190 done_file:
191
192 if (0 != close(fd)) {
193 fprintf(stderr, "Error closing %s: %s\n",
194 outfile, strerror(errno));
195 errorcnt++;
196 }
197
198 return !!errorcnt;
199 }
200
201 DECLARE_FUTIL_COMMAND(load_fmap, do_load_fmap,
202 VBOOT_VERSION_ALL,
203 "Replace the contents of specified FMAP areas",
204 help_and_quit);
205