1 /* 2 * Based on mkimage.c. 3 * 4 * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include "dumpimage.h" 10 #include <image.h> 11 #include <version.h> 12 13 static void usage(void); 14 15 /* image_type_params linked list to maintain registered image types supports */ 16 static struct image_type_params *dumpimage_tparams; 17 18 /* parameters initialized by core will be used by the image type code */ 19 static struct image_tool_params params = { 20 .type = IH_TYPE_KERNEL, 21 }; 22 23 /** 24 * dumpimage_register() - register respective image generation/list support 25 * 26 * the input struct image_type_params is checked and appended to the link 27 * list, if the input structure is already registered, issue an error 28 * 29 * @tparams: Image type parameters 30 */ 31 static void dumpimage_register(struct image_type_params *tparams) 32 { 33 struct image_type_params **tp; 34 35 if (!tparams) { 36 fprintf(stderr, "%s: %s: Null input\n", params.cmdname, 37 __func__); 38 exit(EXIT_FAILURE); 39 } 40 41 /* scan the linked list, check for registry and point the last one */ 42 for (tp = &dumpimage_tparams; *tp != NULL; tp = &(*tp)->next) { 43 if (!strcmp((*tp)->name, tparams->name)) { 44 fprintf(stderr, "%s: %s already registered\n", 45 params.cmdname, tparams->name); 46 return; 47 } 48 } 49 50 /* add input struct entry at the end of link list */ 51 *tp = tparams; 52 /* mark input entry as last entry in the link list */ 53 tparams->next = NULL; 54 55 debug("Registered %s\n", tparams->name); 56 } 57 58 /** 59 * dumpimage_get_type() - find the image type params for a given image type 60 * 61 * Scan all registered image types and check the input type_id for each 62 * supported image type 63 * 64 * @return respective image_type_params pointer. If the input type is not 65 * supported by any of registered image types, returns NULL 66 */ 67 static struct image_type_params *dumpimage_get_type(int type) 68 { 69 struct image_type_params *curr; 70 71 for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { 72 if (curr->check_image_type) { 73 if (!curr->check_image_type(type)) 74 return curr; 75 } 76 } 77 return NULL; 78 } 79 80 /* 81 * dumpimage_verify_print_header() - verifies the image header 82 * 83 * Scan registered image types and verify the image_header for each 84 * supported image type. If verification is successful, this prints 85 * the respective header. 86 * 87 * @return 0 on success, negative if input image format does not match with 88 * any of supported image types 89 */ 90 static int dumpimage_verify_print_header(void *ptr, struct stat *sbuf) 91 { 92 int retval = -1; 93 struct image_type_params *curr; 94 95 for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { 96 if (curr->verify_header) { 97 retval = curr->verify_header((unsigned char *)ptr, 98 sbuf->st_size, ¶ms); 99 if (retval != 0) 100 continue; 101 /* 102 * Print the image information if verify is 103 * successful 104 */ 105 if (curr->print_header) { 106 curr->print_header(ptr); 107 } else { 108 fprintf(stderr, 109 "%s: print_header undefined for %s\n", 110 params.cmdname, curr->name); 111 } 112 break; 113 } 114 } 115 116 return retval; 117 } 118 119 /* 120 * dumpimage_extract_datafile - 121 * 122 * It scans all registered image types, 123 * verifies image_header for each supported image type 124 * if verification is successful, it extracts the desired file, 125 * indexed by pflag, from the image 126 * 127 * returns negative if input image format does not match with any of 128 * supported image types 129 */ 130 static int dumpimage_extract_datafile(void *ptr, struct stat *sbuf) 131 { 132 int retval = -1; 133 struct image_type_params *curr; 134 135 for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { 136 if (curr->verify_header) { 137 retval = curr->verify_header((unsigned char *)ptr, 138 sbuf->st_size, ¶ms); 139 if (retval != 0) 140 continue; 141 /* 142 * Extract the file from the image 143 * if verify is successful 144 */ 145 if (curr->extract_datafile) { 146 curr->extract_datafile(ptr, ¶ms); 147 } else { 148 fprintf(stderr, 149 "%s: extract_datafile undefined for %s\n", 150 params.cmdname, curr->name); 151 break; 152 } 153 } 154 } 155 156 return retval; 157 } 158 159 int main(int argc, char **argv) 160 { 161 int opt; 162 int ifd = -1; 163 struct stat sbuf; 164 char *ptr; 165 int retval = 0; 166 struct image_type_params *tparams = NULL; 167 168 /* Init all image generation/list support */ 169 register_image_tool(dumpimage_register); 170 171 params.cmdname = *argv; 172 173 while ((opt = getopt(argc, argv, "li:o:p:V")) != -1) { 174 switch (opt) { 175 case 'l': 176 params.lflag = 1; 177 break; 178 case 'i': 179 params.imagefile = optarg; 180 params.iflag = 1; 181 break; 182 case 'o': 183 params.outfile = optarg; 184 break; 185 case 'p': 186 params.pflag = strtoul(optarg, &ptr, 10); 187 if (*ptr) { 188 fprintf(stderr, 189 "%s: invalid file position %s\n", 190 params.cmdname, *argv); 191 exit(EXIT_FAILURE); 192 } 193 break; 194 case 'V': 195 printf("dumpimage version %s\n", PLAIN_VERSION); 196 exit(EXIT_SUCCESS); 197 default: 198 usage(); 199 } 200 } 201 202 if (optind >= argc) 203 usage(); 204 205 /* set tparams as per input type_id */ 206 tparams = dumpimage_get_type(params.type); 207 if (tparams == NULL) { 208 fprintf(stderr, "%s: unsupported type %s\n", 209 params.cmdname, genimg_get_type_name(params.type)); 210 exit(EXIT_FAILURE); 211 } 212 213 /* 214 * check the passed arguments parameters meets the requirements 215 * as per image type to be generated/listed 216 */ 217 if (tparams->check_params) { 218 if (tparams->check_params(¶ms)) 219 usage(); 220 } 221 222 if (params.iflag) 223 params.datafile = argv[optind]; 224 else 225 params.imagefile = argv[optind]; 226 if (!params.outfile) 227 params.outfile = params.datafile; 228 229 ifd = open(params.imagefile, O_RDONLY|O_BINARY); 230 if (ifd < 0) { 231 fprintf(stderr, "%s: Can't open \"%s\": %s\n", 232 params.cmdname, params.imagefile, 233 strerror(errno)); 234 exit(EXIT_FAILURE); 235 } 236 237 if (params.lflag || params.iflag) { 238 if (fstat(ifd, &sbuf) < 0) { 239 fprintf(stderr, "%s: Can't stat \"%s\": %s\n", 240 params.cmdname, params.imagefile, 241 strerror(errno)); 242 exit(EXIT_FAILURE); 243 } 244 245 if ((unsigned)sbuf.st_size < tparams->header_size) { 246 fprintf(stderr, 247 "%s: Bad size: \"%s\" is not valid image\n", 248 params.cmdname, params.imagefile); 249 exit(EXIT_FAILURE); 250 } 251 252 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); 253 if (ptr == MAP_FAILED) { 254 fprintf(stderr, "%s: Can't read \"%s\": %s\n", 255 params.cmdname, params.imagefile, 256 strerror(errno)); 257 exit(EXIT_FAILURE); 258 } 259 260 /* 261 * Both calls bellow scan through dumpimage registry for all 262 * supported image types and verify the input image file 263 * header for match 264 */ 265 if (params.iflag) { 266 /* 267 * Extract the data files from within the matched 268 * image type. Returns the error code if not matched 269 */ 270 retval = dumpimage_extract_datafile(ptr, &sbuf); 271 } else { 272 /* 273 * Print the image information for matched image type 274 * Returns the error code if not matched 275 */ 276 retval = dumpimage_verify_print_header(ptr, &sbuf); 277 } 278 279 (void)munmap((void *)ptr, sbuf.st_size); 280 (void)close(ifd); 281 282 return retval; 283 } 284 285 (void)close(ifd); 286 287 return EXIT_SUCCESS; 288 } 289 290 static void usage(void) 291 { 292 fprintf(stderr, "Usage: %s -l image\n" 293 " -l ==> list image header information\n", 294 params.cmdname); 295 fprintf(stderr, 296 " %s -i image [-p position] [-o outfile] data_file\n" 297 " -i ==> extract from the 'image' a specific 'data_file'" 298 ", indexed by 'position' (starting at 0)\n", 299 params.cmdname); 300 fprintf(stderr, 301 " %s -V ==> print version information and exit\n", 302 params.cmdname); 303 304 exit(EXIT_FAILURE); 305 } 306