Home | History | Annotate | Download | only in futility
      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