mkimage.c 16.2 KB
Newer Older
wdenk's avatar
wdenk committed
1
/*
2 3
 * (C) Copyright 2008 Semihalf
 *
4
 * (C) Copyright 2000-2009
wdenk's avatar
wdenk committed
5 6
 * DENX Software Engineering
 * Wolfgang Denk, wd@denx.de
7
 *
8
 * SPDX-License-Identifier:	GPL-2.0+
wdenk's avatar
wdenk committed
9 10
 */

11
#include "mkimage.h"
wdenk's avatar
wdenk committed
12
#include <image.h>
13
#include <version.h>
14 15 16 17

static void copy_file(int, const char *, int);

/* parameters initialized by core will be used by the image type code */
18
static struct image_tool_params params = {
19 20 21 22 23
	.os = IH_OS_LINUX,
	.arch = IH_ARCH_PPC,
	.type = IH_TYPE_KERNEL,
	.comp = IH_COMP_GZIP,
	.dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
24
	.imagename = "",
25
	.imagename2 = "",
26 27
};

28 29 30 31 32 33 34 35 36 37 38 39
static enum ih_category cur_category;

static int h_compare_category_name(const void *vtype1, const void *vtype2)
{
	const int *type1 = vtype1;
	const int *type2 = vtype2;
	const char *name1 = genimg_get_cat_short_name(cur_category, *type1);
	const char *name2 = genimg_get_cat_short_name(cur_category, *type2);

	return strcmp(name1, name2);
}

40
static int show_valid_options(enum ih_category category)
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
{
	int *order;
	int count;
	int item;
	int i;

	count = genimg_get_cat_count(category);
	order = calloc(count, sizeof(*order));
	if (!order)
		return -ENOMEM;

	/* Sort the names in order of short name for easier reading */
	for (item = 0; item < count; item++)
		order[item] = item;
	cur_category = category;
	qsort(order, count, sizeof(int), h_compare_category_name);

	fprintf(stderr, "\nInvalid %s, supported are:\n",
		genimg_get_cat_desc(category));
	for (i = 0; i < count; i++) {
		item = order[i];
		fprintf(stderr, "\t%-15s  %s\n",
			genimg_get_cat_short_name(category, item),
			genimg_get_cat_name(category, item));
	}
	fprintf(stderr, "\n");

	return 0;
}

71
static void usage(const char *msg)
72
{
73
	fprintf(stderr, "Error: %s\n", msg);
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
	fprintf(stderr, "Usage: %s -l image\n"
			 "          -l ==> list image header information\n",
		params.cmdname);
	fprintf(stderr,
		"       %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
		"          -A ==> set architecture to 'arch'\n"
		"          -O ==> set operating system to 'os'\n"
		"          -T ==> set image type to 'type'\n"
		"          -C ==> set compression type 'comp'\n"
		"          -a ==> set load address to 'addr' (hex)\n"
		"          -e ==> set entry point to 'ep' (hex)\n"
		"          -n ==> set image name to 'name'\n"
		"          -d ==> use image data from 'datafile'\n"
		"          -x ==> set XIP (execute in place)\n",
		params.cmdname);
	fprintf(stderr,
90 91
		"       %s [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] fit-image\n"
		"           <dtb> file is used with -f auto, it may occour multiple times.\n",
92 93 94 95 96 97
		params.cmdname);
	fprintf(stderr,
		"          -D => set all options for device tree compiler\n"
		"          -f => input filename for FIT source\n");
#ifdef CONFIG_FIT_SIGNATURE
	fprintf(stderr,
98 99
		"Signing / verified boot options: [-E] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r]\n"
		"          -E => place data outside of the FIT structure\n"
100 101 102 103
		"          -k => set directory containing private keys\n"
		"          -K => write public keys to this .dtb file\n"
		"          -c => add comment in signature node\n"
		"          -F => re-sign existing FIT image\n"
104
		"          -p => place external data at a static position\n"
105 106 107 108 109 110 111 112 113 114 115 116
		"          -r => mark keys used as 'required' in dtb\n");
#else
	fprintf(stderr,
		"Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
#endif
	fprintf(stderr, "       %s -V ==> print version information and exit\n",
		params.cmdname);
	fprintf(stderr, "Use -T to see a list of available image types\n");

	exit(EXIT_FAILURE);
}

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static int add_content(int type, const char *fname)
{
	struct content_info *cont;

	cont = calloc(1, sizeof(*cont));
	if (!cont)
		return -1;
	cont->type = type;
	cont->fname = fname;
	if (params.content_tail)
		params.content_tail->next = cont;
	else
		params.content_head = cont;
	params.content_tail = cont;

	return 0;
}

135
static void process_args(int argc, char **argv)
wdenk's avatar
wdenk committed
136
{
137
	char *ptr;
138 139
	int type = IH_TYPE_INVALID;
	char *datafile = NULL;
140 141 142
	int opt;

	while ((opt = getopt(argc, argv,
143
			     "a:A:b:c:C:d:D:e:Ef:Fk:K:ln:p:O:rR:qsT:vVx")) != -1) {
144
		switch (opt) {
145 146 147 148 149 150 151
		case 'a':
			params.addr = strtoull(optarg, &ptr, 16);
			if (*ptr) {
				fprintf(stderr, "%s: invalid load address %s\n",
					params.cmdname, optarg);
				exit(EXIT_FAILURE);
			}
152 153 154
			break;
		case 'A':
			params.arch = genimg_get_arch_id(optarg);
155 156
			if (params.arch < 0) {
				show_valid_options(IH_ARCH);
157
				usage("Invalid architecture");
158
			}
159
			break;
160
		case 'b':
161
			if (add_content(IH_TYPE_FLATDT, optarg)) {
162 163 164 165 166
				fprintf(stderr,
					"%s: Out of memory adding content '%s'",
					params.cmdname, optarg);
				exit(EXIT_FAILURE);
			}
167
			break;
168 169 170 171 172
		case 'c':
			params.comment = optarg;
			break;
		case 'C':
			params.comp = genimg_get_comp_id(optarg);
173 174
			if (params.comp < 0) {
				show_valid_options(IH_COMP);
175
				usage("Invalid compression type");
176
			}
177 178 179 180 181
			break;
		case 'd':
			params.datafile = optarg;
			params.dflag = 1;
			break;
182 183 184
		case 'D':
			params.dtc = optarg;
			break;
185 186 187 188 189 190
		case 'e':
			params.ep = strtoull(optarg, &ptr, 16);
			if (*ptr) {
				fprintf(stderr, "%s: invalid entry point %s\n",
					params.cmdname, optarg);
				exit(EXIT_FAILURE);
wdenk's avatar
wdenk committed
191
			}
192 193
			params.eflag = 1;
			break;
194 195 196
		case 'E':
			params.external_data = true;
			break;
197
		case 'f':
198 199
			datafile = optarg;
			params.auto_its = !strcmp(datafile, "auto");
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
			/* no break */
		case 'F':
			/*
			 * The flattened image tree (FIT) format
			 * requires a flattened device tree image type
			 */
			params.type = IH_TYPE_FLATDT;
			params.fflag = 1;
			break;
		case 'k':
			params.keydir = optarg;
			break;
		case 'K':
			params.keydest = optarg;
			break;
215 216 217
		case 'l':
			params.lflag = 1;
			break;
218 219 220
		case 'n':
			params.imagename = optarg;
			break;
221 222
		case 'O':
			params.os = genimg_get_os_id(optarg);
223 224
			if (params.os < 0) {
				show_valid_options(IH_OS);
225
				usage("Invalid operating system");
226
			}
227
			break;
228 229 230 231 232 233 234
		case 'p':
			params.external_offset = strtoull(optarg, &ptr, 16);
			if (*ptr) {
				fprintf(stderr, "%s: invalid offset size %s\n",
					params.cmdname, optarg);
				exit(EXIT_FAILURE);
			}
235
			break;
Simon Glass's avatar
Simon Glass committed
236 237 238
		case 'q':
			params.quiet = 1;
			break;
239 240 241 242 243 244 245 246 247 248 249 250 251
		case 'r':
			params.require_keys = 1;
			break;
		case 'R':
			/*
			 * This entry is for the second configuration
			 * file, if only one is not enough.
			 */
			params.imagename2 = optarg;
			break;
		case 's':
			params.skipcpy = 1;
			break;
252
		case 'T':
253 254
			type = genimg_get_type_id(optarg);
			if (type < 0) {
255
				show_valid_options(IH_TYPE);
256
				usage("Invalid image type");
257 258
			}
			break;
259 260 261 262 263 264 265 266 267 268
		case 'v':
			params.vflag++;
			break;
		case 'V':
			printf("mkimage version %s\n", PLAIN_VERSION);
			exit(EXIT_SUCCESS);
		case 'x':
			params.xflag++;
			break;
		default:
269
			usage("Invalid option");
wdenk's avatar
wdenk committed
270 271 272
		}
	}

273 274
	/* The last parameter is expected to be the imagefile */
	if (optind < argc)
275 276
		params.imagefile = argv[optind];

277 278 279 280 281 282
	/*
	 * For auto-generated FIT images we need to know the image type to put
	 * in the FIT, which is separate from the file's image type (which
	 * will always be IH_TYPE_FLATDT in this case).
	 */
	if (params.type == IH_TYPE_FLATDT) {
283
		params.fit_image_type = type ? type : IH_TYPE_KERNEL;
284
		/* For auto_its, datafile is always 'auto' */
285 286
		if (!params.auto_its)
			params.datafile = datafile;
287 288
		else if (!params.datafile)
			usage("Missing data file for auto-FIT (use -d)");
289 290 291 292 293
	} else if (type != IH_TYPE_INVALID) {
		params.type = type;
	}

	if (!params.imagefile)
294
		usage("Missing output filename");
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
}

int main(int argc, char **argv)
{
	int ifd = -1;
	struct stat sbuf;
	char *ptr;
	int retval = 0;
	struct image_type_params *tparams = NULL;
	int pad_len = 0;
	int dfd;

	params.cmdname = *argv;
	params.addr = 0;
	params.ep = 0;

	process_args(argc, argv);
312 313

	/* set tparams as per input type_id */
314
	tparams = imagetool_get_type(params.type);
315 316 317 318 319
	if (tparams == NULL) {
		fprintf (stderr, "%s: unsupported type %s\n",
			params.cmdname, genimg_get_type_name(params.type));
		exit (EXIT_FAILURE);
	}
wdenk's avatar
wdenk committed
320

321 322 323 324 325 326
	/*
	 * check the passed arguments parameters meets the requirements
	 * as per image type to be generated/listed
	 */
	if (tparams->check_params)
		if (tparams->check_params (&params))
327
			usage("Bad parameters for image type");
328 329 330

	if (!params.eflag) {
		params.ep = params.addr;
wdenk's avatar
wdenk committed
331
		/* If XIP, entry point must be after the U-Boot header */
332 333
		if (params.xflag)
			params.ep += tparams->header_size;
wdenk's avatar
wdenk committed
334 335
	}

336 337 338 339 340 341 342 343 344
	if (params.fflag){
		if (tparams->fflag_handle)
			/*
			 * in some cases, some additional processing needs
			 * to be done if fflag is defined
			 *
			 * For ex. fit_handle_file for Fit file support
			 */
			retval = tparams->fflag_handle(&params);
wdenk's avatar
wdenk committed
345

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
		if (retval != EXIT_SUCCESS)
			exit (retval);
	}

	if (params.lflag || params.fflag) {
		ifd = open (params.imagefile, O_RDONLY|O_BINARY);
	} else {
		ifd = open (params.imagefile,
			O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
	}

	if (ifd < 0) {
		fprintf (stderr, "%s: Can't open %s: %s\n",
			params.cmdname, params.imagefile,
			strerror(errno));
		exit (EXIT_FAILURE);
wdenk's avatar
wdenk committed
362 363
	}

364
	if (params.lflag || params.fflag) {
wdenk's avatar
wdenk committed
365 366 367 368 369
		/*
		 * list header information of existing image
		 */
		if (fstat(ifd, &sbuf) < 0) {
			fprintf (stderr, "%s: Can't stat %s: %s\n",
370 371
				params.cmdname, params.imagefile,
				strerror(errno));
wdenk's avatar
wdenk committed
372 373 374
			exit (EXIT_FAILURE);
		}

375
		if ((unsigned)sbuf.st_size < tparams->header_size) {
wdenk's avatar
wdenk committed
376
			fprintf (stderr,
377 378
				"%s: Bad size: \"%s\" is not valid image\n",
				params.cmdname, params.imagefile);
wdenk's avatar
wdenk committed
379 380 381
			exit (EXIT_FAILURE);
		}

382 383
		ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
		if (ptr == MAP_FAILED) {
wdenk's avatar
wdenk committed
384
			fprintf (stderr, "%s: Can't read %s: %s\n",
385 386
				params.cmdname, params.imagefile,
				strerror(errno));
wdenk's avatar
wdenk committed
387 388 389
			exit (EXIT_FAILURE);
		}

390 391 392 393 394 395
		/*
		 * scan through mkimage registry for all supported image types
		 * and verify the input image file header for match
		 * Print the image information for matched image type
		 * Returns the error code if not matched
		 */
396 397
		retval = imagetool_verify_print_header(ptr, &sbuf,
				tparams, &params);
wdenk's avatar
wdenk committed
398 399 400 401

		(void) munmap((void *)ptr, sbuf.st_size);
		(void) close (ifd);

402
		exit (retval);
wdenk's avatar
wdenk committed
403 404
	}

405
	if ((params.type != IH_TYPE_MULTI) && (params.type != IH_TYPE_SCRIPT)) {
406 407 408 409 410 411 412
		dfd = open(params.datafile, O_RDONLY | O_BINARY);
		if (dfd < 0) {
			fprintf(stderr, "%s: Can't open %s: %s\n",
				params.cmdname, params.datafile,
				strerror(errno));
			exit(EXIT_FAILURE);
		}
413

414 415 416 417 418 419
		if (fstat(dfd, &sbuf) < 0) {
			fprintf(stderr, "%s: Can't stat %s: %s\n",
				params.cmdname, params.datafile,
				strerror(errno));
			exit(EXIT_FAILURE);
		}
420

421 422 423
		params.file_size = sbuf.st_size + tparams->header_size;
		close(dfd);
	}
424

wdenk's avatar
wdenk committed
425
	/*
426 427 428 429
	 * In case there an header with a variable
	 * length will be added, the corresponding
	 * function is called. This is responsible to
	 * allocate memory for the header itself.
wdenk's avatar
wdenk committed
430
	 */
431
	if (tparams->vrec_header)
432
		pad_len = tparams->vrec_header(&params, tparams);
433 434
	else
		memset(tparams->hdr, 0, tparams->header_size);
wdenk's avatar
wdenk committed
435

436 437
	if (write(ifd, tparams->hdr, tparams->header_size)
					!= tparams->header_size) {
wdenk's avatar
wdenk committed
438
		fprintf (stderr, "%s: Write error on %s: %s\n",
439
			params.cmdname, params.imagefile, strerror(errno));
wdenk's avatar
wdenk committed
440 441 442
		exit (EXIT_FAILURE);
	}

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
	if (!params.skipcpy) {
		if (params.type == IH_TYPE_MULTI ||
		    params.type == IH_TYPE_SCRIPT) {
			char *file = params.datafile;
			uint32_t size;

			for (;;) {
				char *sep = NULL;

				if (file) {
					if ((sep = strchr(file, ':')) != NULL) {
						*sep = '\0';
					}

					if (stat (file, &sbuf) < 0) {
						fprintf (stderr, "%s: Can't stat %s: %s\n",
							 params.cmdname, file, strerror(errno));
						exit (EXIT_FAILURE);
					}
					size = cpu_to_uimage (sbuf.st_size);
				} else {
					size = 0;
wdenk's avatar
wdenk committed
465 466
				}

467 468 469 470
				if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
					fprintf (stderr, "%s: Write error on %s: %s\n",
						 params.cmdname, params.imagefile,
						 strerror(errno));
wdenk's avatar
wdenk committed
471 472 473
					exit (EXIT_FAILURE);
				}

474 475 476
				if (!file) {
					break;
				}
wdenk's avatar
wdenk committed
477

478 479 480 481 482 483
				if (sep) {
					*sep = ':';
					file = sep + 1;
				} else {
					file = NULL;
				}
wdenk's avatar
wdenk committed
484 485
			}

486
			file = params.datafile;
wdenk's avatar
wdenk committed
487

488 489 490 491 492 493 494 495 496 497 498
			for (;;) {
				char *sep = strchr(file, ':');
				if (sep) {
					*sep = '\0';
					copy_file (ifd, file, 1);
					*sep++ = ':';
					file = sep;
				} else {
					copy_file (ifd, file, 0);
					break;
				}
wdenk's avatar
wdenk committed
499
			}
500 501 502
		} else if (params.type == IH_TYPE_PBLIMAGE) {
			/* PBL has special Image format, implements its' own */
			pbl_load_uboot(ifd, &params);
503
		} else {
504
			copy_file(ifd, params.datafile, pad_len);
wdenk's avatar
wdenk committed
505 506 507 508
		}
	}

	/* We're a bit of paranoid */
509 510 511
#if defined(_POSIX_SYNCHRONIZED_IO) && \
   !defined(__sun__) && \
   !defined(__FreeBSD__) && \
512
   !defined(__OpenBSD__) && \
513
   !defined(__APPLE__)
wdenk's avatar
wdenk committed
514 515 516 517 518 519 520
	(void) fdatasync (ifd);
#else
	(void) fsync (ifd);
#endif

	if (fstat(ifd, &sbuf) < 0) {
		fprintf (stderr, "%s: Can't stat %s: %s\n",
521
			params.cmdname, params.imagefile, strerror(errno));
wdenk's avatar
wdenk committed
522 523
		exit (EXIT_FAILURE);
	}
524
	params.file_size = sbuf.st_size;
wdenk's avatar
wdenk committed
525

526 527
	ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
	if (ptr == MAP_FAILED) {
wdenk's avatar
wdenk committed
528
		fprintf (stderr, "%s: Can't map %s: %s\n",
529
			params.cmdname, params.imagefile, strerror(errno));
wdenk's avatar
wdenk committed
530 531 532
		exit (EXIT_FAILURE);
	}

533 534 535 536 537 538 539 540
	/* Setup the image header as per input image type*/
	if (tparams->set_header)
		tparams->set_header (ptr, &sbuf, ifd, &params);
	else {
		fprintf (stderr, "%s: Can't set header for %s: %s\n",
			params.cmdname, tparams->name, strerror(errno));
		exit (EXIT_FAILURE);
	}
wdenk's avatar
wdenk committed
541

542 543 544 545 546 547 548 549
	/* Print the image information by processing image header */
	if (tparams->print_header)
		tparams->print_header (ptr);
	else {
		fprintf (stderr, "%s: Can't print header for %s: %s\n",
			params.cmdname, tparams->name, strerror(errno));
		exit (EXIT_FAILURE);
	}
wdenk's avatar
wdenk committed
550 551 552 553

	(void) munmap((void *)ptr, sbuf.st_size);

	/* We're a bit of paranoid */
554 555 556
#if defined(_POSIX_SYNCHRONIZED_IO) && \
   !defined(__sun__) && \
   !defined(__FreeBSD__) && \
557
   !defined(__OpenBSD__) && \
558
   !defined(__APPLE__)
wdenk's avatar
wdenk committed
559 560 561 562 563 564 565
	(void) fdatasync (ifd);
#else
	(void) fsync (ifd);
#endif

	if (close(ifd)) {
		fprintf (stderr, "%s: Write error on %s: %s\n",
566
			params.cmdname, params.imagefile, strerror(errno));
wdenk's avatar
wdenk committed
567 568 569 570 571 572 573 574 575 576 577 578 579 580
		exit (EXIT_FAILURE);
	}

	exit (EXIT_SUCCESS);
}

static void
copy_file (int ifd, const char *datafile, int pad)
{
	int dfd;
	struct stat sbuf;
	unsigned char *ptr;
	int tail;
	int zero = 0;
581
	uint8_t zeros[4096];
wdenk's avatar
wdenk committed
582 583
	int offset = 0;
	int size;
584
	struct image_type_params *tparams = imagetool_get_type(params.type);
wdenk's avatar
wdenk committed
585

586 587
	memset(zeros, 0, sizeof(zeros));

588
	if (params.vflag) {
wdenk's avatar
wdenk committed
589 590 591
		fprintf (stderr, "Adding Image %s\n", datafile);
	}

592
	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
wdenk's avatar
wdenk committed
593
		fprintf (stderr, "%s: Can't open %s: %s\n",
594
			params.cmdname, datafile, strerror(errno));
wdenk's avatar
wdenk committed
595 596 597 598 599
		exit (EXIT_FAILURE);
	}

	if (fstat(dfd, &sbuf) < 0) {
		fprintf (stderr, "%s: Can't stat %s: %s\n",
600
			params.cmdname, datafile, strerror(errno));
wdenk's avatar
wdenk committed
601 602 603
		exit (EXIT_FAILURE);
	}

604 605
	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
	if (ptr == MAP_FAILED) {
wdenk's avatar
wdenk committed
606
		fprintf (stderr, "%s: Can't read %s: %s\n",
607
			params.cmdname, datafile, strerror(errno));
wdenk's avatar
wdenk committed
608 609 610
		exit (EXIT_FAILURE);
	}

611
	if (params.xflag) {
wdenk's avatar
wdenk committed
612 613 614 615 616 617 618
		unsigned char *p = NULL;
		/*
		 * XIP: do not append the image_header_t at the
		 * beginning of the file, but consume the space
		 * reserved for it.
		 */

619
		if ((unsigned)sbuf.st_size < tparams->header_size) {
wdenk's avatar
wdenk committed
620 621
			fprintf (stderr,
				"%s: Bad size: \"%s\" is too small for XIP\n",
622
				params.cmdname, datafile);
wdenk's avatar
wdenk committed
623 624 625
			exit (EXIT_FAILURE);
		}

626
		for (p = ptr; p < ptr + tparams->header_size; p++) {
wdenk's avatar
wdenk committed
627 628 629
			if ( *p != 0xff ) {
				fprintf (stderr,
					"%s: Bad file: \"%s\" has invalid buffer for XIP\n",
630
					params.cmdname, datafile);
wdenk's avatar
wdenk committed
631 632 633 634
				exit (EXIT_FAILURE);
			}
		}

635
		offset = tparams->header_size;
wdenk's avatar
wdenk committed
636 637 638 639 640
	}

	size = sbuf.st_size - offset;
	if (write(ifd, ptr + offset, size) != size) {
		fprintf (stderr, "%s: Write error on %s: %s\n",
641
			params.cmdname, params.imagefile, strerror(errno));
wdenk's avatar
wdenk committed
642 643 644
		exit (EXIT_FAILURE);
	}

645 646
	tail = size % 4;
	if ((pad == 1) && (tail != 0)) {
wdenk's avatar
wdenk committed
647 648 649

		if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
			fprintf (stderr, "%s: Write error on %s: %s\n",
650 651
				params.cmdname, params.imagefile,
				strerror(errno));
wdenk's avatar
wdenk committed
652 653
			exit (EXIT_FAILURE);
		}
654
	} else if (pad > 1) {
655 656 657 658 659 660 661 662 663 664 665 666
		while (pad > 0) {
			int todo = sizeof(zeros);

			if (todo > pad)
				todo = pad;
			if (write(ifd, (char *)&zeros, todo) != todo) {
				fprintf(stderr, "%s: Write error on %s: %s\n",
					params.cmdname, params.imagefile,
					strerror(errno));
				exit(EXIT_FAILURE);
			}
			pad -= todo;
667
		}
wdenk's avatar
wdenk committed
668 669 670 671 672
	}

	(void) munmap((void *)ptr, sbuf.st_size);
	(void) close (dfd);
}