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 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 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 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