xref: /openbmc/u-boot/tools/mkimage.c (revision fc5ca3ab)
1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   * (C) Copyright 2008 Semihalf
4   *
5   * (C) Copyright 2000-2009
6   * DENX Software Engineering
7   * Wolfgang Denk, wd@denx.de
8   */
9  
10  #include "mkimage.h"
11  #include "imximage.h"
12  #include <image.h>
13  #include <version.h>
14  
15  static void copy_file(int, const char *, int);
16  
17  /* parameters initialized by core will be used by the image type code */
18  static struct image_tool_params params = {
19  	.os = IH_OS_LINUX,
20  	.arch = IH_ARCH_PPC,
21  	.type = IH_TYPE_KERNEL,
22  	.comp = IH_COMP_GZIP,
23  	.dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
24  	.imagename = "",
25  	.imagename2 = "",
26  };
27  
28  static enum ih_category cur_category;
29  
30  static int h_compare_category_name(const void *vtype1, const void *vtype2)
31  {
32  	const int *type1 = vtype1;
33  	const int *type2 = vtype2;
34  	const char *name1 = genimg_get_cat_short_name(cur_category, *type1);
35  	const char *name2 = genimg_get_cat_short_name(cur_category, *type2);
36  
37  	return strcmp(name1, name2);
38  }
39  
40  static int show_valid_options(enum ih_category category)
41  {
42  	int *order;
43  	int count;
44  	int item;
45  	int i;
46  
47  	count = genimg_get_cat_count(category);
48  	order = calloc(count, sizeof(*order));
49  	if (!order)
50  		return -ENOMEM;
51  
52  	/* Sort the names in order of short name for easier reading */
53  	for (item = 0; item < count; item++)
54  		order[item] = item;
55  	cur_category = category;
56  	qsort(order, count, sizeof(int), h_compare_category_name);
57  
58  	fprintf(stderr, "\nInvalid %s, supported are:\n",
59  		genimg_get_cat_desc(category));
60  	for (i = 0; i < count; i++) {
61  		item = order[i];
62  		fprintf(stderr, "\t%-15s  %s\n",
63  			genimg_get_cat_short_name(category, item),
64  			genimg_get_cat_name(category, item));
65  	}
66  	fprintf(stderr, "\n");
67  	free(order);
68  
69  	return 0;
70  }
71  
72  static void usage(const char *msg)
73  {
74  	fprintf(stderr, "Error: %s\n", msg);
75  	fprintf(stderr, "Usage: %s -l image\n"
76  			 "          -l ==> list image header information\n",
77  		params.cmdname);
78  	fprintf(stderr,
79  		"       %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
80  		"          -A ==> set architecture to 'arch'\n"
81  		"          -O ==> set operating system to 'os'\n"
82  		"          -T ==> set image type to 'type'\n"
83  		"          -C ==> set compression type 'comp'\n"
84  		"          -a ==> set load address to 'addr' (hex)\n"
85  		"          -e ==> set entry point to 'ep' (hex)\n"
86  		"          -n ==> set image name to 'name'\n"
87  		"          -d ==> use image data from 'datafile'\n"
88  		"          -x ==> set XIP (execute in place)\n",
89  		params.cmdname);
90  	fprintf(stderr,
91  		"       %s [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] [-i <ramdisk.cpio.gz>] fit-image\n"
92  		"           <dtb> file is used with -f auto, it may occur multiple times.\n",
93  		params.cmdname);
94  	fprintf(stderr,
95  		"          -D => set all options for device tree compiler\n"
96  		"          -f => input filename for FIT source\n"
97  		"          -i => input filename for ramdisk file\n");
98  #ifdef CONFIG_FIT_SIGNATURE
99  	fprintf(stderr,
100  		"Signing / verified boot options: [-E] [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n"
101  		"          -E => place data outside of the FIT structure\n"
102  		"          -k => set directory containing private keys\n"
103  		"          -K => write public keys to this .dtb file\n"
104  		"          -c => add comment in signature node\n"
105  		"          -F => re-sign existing FIT image\n"
106  		"          -p => place external data at a static position\n"
107  		"          -r => mark keys used as 'required' in dtb\n"
108  		"          -N => engine to use for signing (pkcs11)\n");
109  #else
110  	fprintf(stderr,
111  		"Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
112  #endif
113  	fprintf(stderr, "       %s -V ==> print version information and exit\n",
114  		params.cmdname);
115  	fprintf(stderr, "Use '-T list' to see a list of available image types\n");
116  
117  	exit(EXIT_FAILURE);
118  }
119  
120  static int add_content(int type, const char *fname)
121  {
122  	struct content_info *cont;
123  
124  	cont = calloc(1, sizeof(*cont));
125  	if (!cont)
126  		return -1;
127  	cont->type = type;
128  	cont->fname = fname;
129  	if (params.content_tail)
130  		params.content_tail->next = cont;
131  	else
132  		params.content_head = cont;
133  	params.content_tail = cont;
134  
135  	return 0;
136  }
137  
138  static void process_args(int argc, char **argv)
139  {
140  	char *ptr;
141  	int type = IH_TYPE_INVALID;
142  	char *datafile = NULL;
143  	int opt;
144  
145  	while ((opt = getopt(argc, argv,
146  			     "a:A:b:c:C:d:D:e:Ef:Fk:i:K:ln:N:p:O:rR:qsT:vVx")) != -1) {
147  		switch (opt) {
148  		case 'a':
149  			params.addr = strtoull(optarg, &ptr, 16);
150  			if (*ptr) {
151  				fprintf(stderr, "%s: invalid load address %s\n",
152  					params.cmdname, optarg);
153  				exit(EXIT_FAILURE);
154  			}
155  			break;
156  		case 'A':
157  			params.arch = genimg_get_arch_id(optarg);
158  			if (params.arch < 0) {
159  				show_valid_options(IH_ARCH);
160  				usage("Invalid architecture");
161  			}
162  			break;
163  		case 'b':
164  			if (add_content(IH_TYPE_FLATDT, optarg)) {
165  				fprintf(stderr,
166  					"%s: Out of memory adding content '%s'",
167  					params.cmdname, optarg);
168  				exit(EXIT_FAILURE);
169  			}
170  			break;
171  		case 'c':
172  			params.comment = optarg;
173  			break;
174  		case 'C':
175  			params.comp = genimg_get_comp_id(optarg);
176  			if (params.comp < 0) {
177  				show_valid_options(IH_COMP);
178  				usage("Invalid compression type");
179  			}
180  			break;
181  		case 'd':
182  			params.datafile = optarg;
183  			params.dflag = 1;
184  			break;
185  		case 'D':
186  			params.dtc = optarg;
187  			break;
188  		case 'e':
189  			params.ep = strtoull(optarg, &ptr, 16);
190  			if (*ptr) {
191  				fprintf(stderr, "%s: invalid entry point %s\n",
192  					params.cmdname, optarg);
193  				exit(EXIT_FAILURE);
194  			}
195  			params.eflag = 1;
196  			break;
197  		case 'E':
198  			params.external_data = true;
199  			break;
200  		case 'f':
201  			datafile = optarg;
202  			params.auto_its = !strcmp(datafile, "auto");
203  			/* no break */
204  		case 'F':
205  			/*
206  			 * The flattened image tree (FIT) format
207  			 * requires a flattened device tree image type
208  			 */
209  			params.type = IH_TYPE_FLATDT;
210  			params.fflag = 1;
211  			break;
212  		case 'i':
213  			params.fit_ramdisk = optarg;
214  			break;
215  		case 'k':
216  			params.keydir = optarg;
217  			break;
218  		case 'K':
219  			params.keydest = optarg;
220  			break;
221  		case 'l':
222  			params.lflag = 1;
223  			break;
224  		case 'n':
225  			params.imagename = optarg;
226  			break;
227  		case 'N':
228  			params.engine_id = optarg;
229  			break;
230  		case 'O':
231  			params.os = genimg_get_os_id(optarg);
232  			if (params.os < 0) {
233  				show_valid_options(IH_OS);
234  				usage("Invalid operating system");
235  			}
236  			break;
237  		case 'p':
238  			params.external_offset = strtoull(optarg, &ptr, 16);
239  			if (*ptr) {
240  				fprintf(stderr, "%s: invalid offset size %s\n",
241  					params.cmdname, optarg);
242  				exit(EXIT_FAILURE);
243  			}
244  			break;
245  		case 'q':
246  			params.quiet = 1;
247  			break;
248  		case 'r':
249  			params.require_keys = 1;
250  			break;
251  		case 'R':
252  			/*
253  			 * This entry is for the second configuration
254  			 * file, if only one is not enough.
255  			 */
256  			params.imagename2 = optarg;
257  			break;
258  		case 's':
259  			params.skipcpy = 1;
260  			break;
261  		case 'T':
262  			if (strcmp(optarg, "list") == 0) {
263  				show_valid_options(IH_TYPE);
264  				exit(EXIT_SUCCESS);
265  			}
266  			type = genimg_get_type_id(optarg);
267  			if (type < 0) {
268  				show_valid_options(IH_TYPE);
269  				usage("Invalid image type");
270  			}
271  			break;
272  		case 'v':
273  			params.vflag++;
274  			break;
275  		case 'V':
276  			printf("mkimage version %s\n", PLAIN_VERSION);
277  			exit(EXIT_SUCCESS);
278  		case 'x':
279  			params.xflag++;
280  			break;
281  		default:
282  			usage("Invalid option");
283  		}
284  	}
285  
286  	/* The last parameter is expected to be the imagefile */
287  	if (optind < argc)
288  		params.imagefile = argv[optind];
289  
290  	/*
291  	 * For auto-generated FIT images we need to know the image type to put
292  	 * in the FIT, which is separate from the file's image type (which
293  	 * will always be IH_TYPE_FLATDT in this case).
294  	 */
295  	if (params.type == IH_TYPE_FLATDT) {
296  		params.fit_image_type = type ? type : IH_TYPE_KERNEL;
297  		/* For auto_its, datafile is always 'auto' */
298  		if (!params.auto_its)
299  			params.datafile = datafile;
300  		else if (!params.datafile)
301  			usage("Missing data file for auto-FIT (use -d)");
302  	} else if (type != IH_TYPE_INVALID) {
303  		if (type == IH_TYPE_SCRIPT && !params.datafile)
304  			usage("Missing data file for script (use -d)");
305  		params.type = type;
306  	}
307  
308  	if (!params.imagefile)
309  		usage("Missing output filename");
310  }
311  
312  int main(int argc, char **argv)
313  {
314  	int ifd = -1;
315  	struct stat sbuf;
316  	char *ptr;
317  	int retval = 0;
318  	struct image_type_params *tparams = NULL;
319  	int pad_len = 0;
320  	int dfd;
321  	size_t map_len;
322  
323  	params.cmdname = *argv;
324  	params.addr = 0;
325  	params.ep = 0;
326  
327  	process_args(argc, argv);
328  
329  	/* set tparams as per input type_id */
330  	tparams = imagetool_get_type(params.type);
331  	if (tparams == NULL) {
332  		fprintf (stderr, "%s: unsupported type %s\n",
333  			params.cmdname, genimg_get_type_name(params.type));
334  		exit (EXIT_FAILURE);
335  	}
336  
337  	/*
338  	 * check the passed arguments parameters meets the requirements
339  	 * as per image type to be generated/listed
340  	 */
341  	if (tparams->check_params)
342  		if (tparams->check_params (&params))
343  			usage("Bad parameters for image type");
344  
345  	if (!params.eflag) {
346  		params.ep = params.addr;
347  		/* If XIP, entry point must be after the U-Boot header */
348  		if (params.xflag)
349  			params.ep += tparams->header_size;
350  	}
351  
352  	if (params.fflag){
353  		if (tparams->fflag_handle)
354  			/*
355  			 * in some cases, some additional processing needs
356  			 * to be done if fflag is defined
357  			 *
358  			 * For ex. fit_handle_file for Fit file support
359  			 */
360  			retval = tparams->fflag_handle(&params);
361  
362  		if (retval != EXIT_SUCCESS)
363  			exit (retval);
364  	}
365  
366  	if (params.lflag || params.fflag) {
367  		ifd = open (params.imagefile, O_RDONLY|O_BINARY);
368  	} else {
369  		ifd = open (params.imagefile,
370  			O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
371  	}
372  
373  	if (ifd < 0) {
374  		fprintf (stderr, "%s: Can't open %s: %s\n",
375  			params.cmdname, params.imagefile,
376  			strerror(errno));
377  		exit (EXIT_FAILURE);
378  	}
379  
380  	if (params.lflag || params.fflag) {
381  		/*
382  		 * list header information of existing image
383  		 */
384  		if (fstat(ifd, &sbuf) < 0) {
385  			fprintf (stderr, "%s: Can't stat %s: %s\n",
386  				params.cmdname, params.imagefile,
387  				strerror(errno));
388  			exit (EXIT_FAILURE);
389  		}
390  
391  		if ((unsigned)sbuf.st_size < tparams->header_size) {
392  			fprintf (stderr,
393  				"%s: Bad size: \"%s\" is not valid image\n",
394  				params.cmdname, params.imagefile);
395  			exit (EXIT_FAILURE);
396  		}
397  
398  		ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
399  		if (ptr == MAP_FAILED) {
400  			fprintf (stderr, "%s: Can't read %s: %s\n",
401  				params.cmdname, params.imagefile,
402  				strerror(errno));
403  			exit (EXIT_FAILURE);
404  		}
405  
406  		/*
407  		 * scan through mkimage registry for all supported image types
408  		 * and verify the input image file header for match
409  		 * Print the image information for matched image type
410  		 * Returns the error code if not matched
411  		 */
412  		retval = imagetool_verify_print_header(ptr, &sbuf,
413  				tparams, &params);
414  
415  		(void) munmap((void *)ptr, sbuf.st_size);
416  		(void) close (ifd);
417  
418  		exit (retval);
419  	}
420  
421  	if ((params.type != IH_TYPE_MULTI) && (params.type != IH_TYPE_SCRIPT)) {
422  		dfd = open(params.datafile, O_RDONLY | O_BINARY);
423  		if (dfd < 0) {
424  			fprintf(stderr, "%s: Can't open %s: %s\n",
425  				params.cmdname, params.datafile,
426  				strerror(errno));
427  			exit(EXIT_FAILURE);
428  		}
429  
430  		if (fstat(dfd, &sbuf) < 0) {
431  			fprintf(stderr, "%s: Can't stat %s: %s\n",
432  				params.cmdname, params.datafile,
433  				strerror(errno));
434  			exit(EXIT_FAILURE);
435  		}
436  
437  		params.file_size = sbuf.st_size + tparams->header_size;
438  		close(dfd);
439  	}
440  
441  	/*
442  	 * In case there an header with a variable
443  	 * length will be added, the corresponding
444  	 * function is called. This is responsible to
445  	 * allocate memory for the header itself.
446  	 */
447  	if (tparams->vrec_header)
448  		pad_len = tparams->vrec_header(&params, tparams);
449  	else
450  		memset(tparams->hdr, 0, tparams->header_size);
451  
452  	if (write(ifd, tparams->hdr, tparams->header_size)
453  					!= tparams->header_size) {
454  		fprintf (stderr, "%s: Write error on %s: %s\n",
455  			params.cmdname, params.imagefile, strerror(errno));
456  		exit (EXIT_FAILURE);
457  	}
458  
459  	if (!params.skipcpy) {
460  		if (params.type == IH_TYPE_MULTI ||
461  		    params.type == IH_TYPE_SCRIPT) {
462  			char *file = params.datafile;
463  			uint32_t size;
464  
465  			for (;;) {
466  				char *sep = NULL;
467  
468  				if (file) {
469  					if ((sep = strchr(file, ':')) != NULL) {
470  						*sep = '\0';
471  					}
472  
473  					if (stat (file, &sbuf) < 0) {
474  						fprintf (stderr, "%s: Can't stat %s: %s\n",
475  							 params.cmdname, file, strerror(errno));
476  						exit (EXIT_FAILURE);
477  					}
478  					size = cpu_to_uimage (sbuf.st_size);
479  				} else {
480  					size = 0;
481  				}
482  
483  				if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
484  					fprintf (stderr, "%s: Write error on %s: %s\n",
485  						 params.cmdname, params.imagefile,
486  						 strerror(errno));
487  					exit (EXIT_FAILURE);
488  				}
489  
490  				if (!file) {
491  					break;
492  				}
493  
494  				if (sep) {
495  					*sep = ':';
496  					file = sep + 1;
497  				} else {
498  					file = NULL;
499  				}
500  			}
501  
502  			file = params.datafile;
503  
504  			for (;;) {
505  				char *sep = strchr(file, ':');
506  				if (sep) {
507  					*sep = '\0';
508  					copy_file (ifd, file, 1);
509  					*sep++ = ':';
510  					file = sep;
511  				} else {
512  					copy_file (ifd, file, 0);
513  					break;
514  				}
515  			}
516  		} else if (params.type == IH_TYPE_PBLIMAGE) {
517  			/* PBL has special Image format, implements its' own */
518  			pbl_load_uboot(ifd, &params);
519  		} else if (params.type == IH_TYPE_ZYNQMPBIF) {
520  			/* Image file is meta, walk through actual targets */
521  			int ret;
522  
523  			ret = zynqmpbif_copy_image(ifd, &params);
524  			if (ret)
525  				return ret;
526  		} else {
527  			copy_file(ifd, params.datafile, pad_len);
528  		}
529  		if (params.type == IH_TYPE_FIRMWARE_IVT) {
530  			/* Add alignment and IVT */
531  			uint32_t aligned_filesize = (params.file_size + 0x1000
532  					- 1) & ~(0x1000 - 1);
533  			flash_header_v2_t ivt_header = { { 0xd1, 0x2000, 0x40 },
534  					params.addr, 0, 0, 0, params.addr
535  							+ aligned_filesize
536  							- tparams->header_size,
537  					params.addr + aligned_filesize
538  							- tparams->header_size
539  							+ 0x20, 0 };
540  			int i = params.file_size;
541  			for (; i < aligned_filesize; i++) {
542  				if (write(ifd, (char *) &i, 1) != 1) {
543  					fprintf(stderr,
544  							"%s: Write error on %s: %s\n",
545  							params.cmdname,
546  							params.imagefile,
547  							strerror(errno));
548  					exit(EXIT_FAILURE);
549  				}
550  			}
551  			if (write(ifd, &ivt_header, sizeof(flash_header_v2_t))
552  					!= sizeof(flash_header_v2_t)) {
553  				fprintf(stderr, "%s: Write error on %s: %s\n",
554  						params.cmdname,
555  						params.imagefile,
556  						strerror(errno));
557  				exit(EXIT_FAILURE);
558  			}
559  		}
560  	}
561  
562  	/* We're a bit of paranoid */
563  #if defined(_POSIX_SYNCHRONIZED_IO) && \
564     !defined(__sun__) && \
565     !defined(__FreeBSD__) && \
566     !defined(__OpenBSD__) && \
567     !defined(__APPLE__)
568  	(void) fdatasync (ifd);
569  #else
570  	(void) fsync (ifd);
571  #endif
572  
573  	if (fstat(ifd, &sbuf) < 0) {
574  		fprintf (stderr, "%s: Can't stat %s: %s\n",
575  			params.cmdname, params.imagefile, strerror(errno));
576  		exit (EXIT_FAILURE);
577  	}
578  	params.file_size = sbuf.st_size;
579  
580  	map_len = sbuf.st_size;
581  	ptr = mmap(0, map_len, PROT_READ | PROT_WRITE, MAP_SHARED, ifd, 0);
582  	if (ptr == MAP_FAILED) {
583  		fprintf (stderr, "%s: Can't map %s: %s\n",
584  			params.cmdname, params.imagefile, strerror(errno));
585  		exit (EXIT_FAILURE);
586  	}
587  
588  	/* Setup the image header as per input image type*/
589  	if (tparams->set_header)
590  		tparams->set_header (ptr, &sbuf, ifd, &params);
591  	else {
592  		fprintf (stderr, "%s: Can't set header for %s: %s\n",
593  			params.cmdname, tparams->name, strerror(errno));
594  		exit (EXIT_FAILURE);
595  	}
596  
597  	/* Print the image information by processing image header */
598  	if (tparams->print_header)
599  		tparams->print_header (ptr);
600  	else {
601  		fprintf (stderr, "%s: Can't print header for %s\n",
602  			params.cmdname, tparams->name);
603  	}
604  
605  	(void)munmap((void *)ptr, map_len);
606  
607  	/* We're a bit of paranoid */
608  #if defined(_POSIX_SYNCHRONIZED_IO) && \
609     !defined(__sun__) && \
610     !defined(__FreeBSD__) && \
611     !defined(__OpenBSD__) && \
612     !defined(__APPLE__)
613  	(void) fdatasync (ifd);
614  #else
615  	(void) fsync (ifd);
616  #endif
617  
618  	if (close(ifd)) {
619  		fprintf (stderr, "%s: Write error on %s: %s\n",
620  			params.cmdname, params.imagefile, strerror(errno));
621  		exit (EXIT_FAILURE);
622  	}
623  
624  	exit (EXIT_SUCCESS);
625  }
626  
627  static void
628  copy_file (int ifd, const char *datafile, int pad)
629  {
630  	int dfd;
631  	struct stat sbuf;
632  	unsigned char *ptr;
633  	int tail;
634  	int zero = 0;
635  	uint8_t zeros[4096];
636  	int offset = 0;
637  	int size;
638  	struct image_type_params *tparams = imagetool_get_type(params.type);
639  
640  	memset(zeros, 0, sizeof(zeros));
641  
642  	if (params.vflag) {
643  		fprintf (stderr, "Adding Image %s\n", datafile);
644  	}
645  
646  	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
647  		fprintf (stderr, "%s: Can't open %s: %s\n",
648  			params.cmdname, datafile, strerror(errno));
649  		exit (EXIT_FAILURE);
650  	}
651  
652  	if (fstat(dfd, &sbuf) < 0) {
653  		fprintf (stderr, "%s: Can't stat %s: %s\n",
654  			params.cmdname, datafile, strerror(errno));
655  		exit (EXIT_FAILURE);
656  	}
657  
658  	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
659  	if (ptr == MAP_FAILED) {
660  		fprintf (stderr, "%s: Can't read %s: %s\n",
661  			params.cmdname, datafile, strerror(errno));
662  		exit (EXIT_FAILURE);
663  	}
664  
665  	if (params.xflag) {
666  		unsigned char *p = NULL;
667  		/*
668  		 * XIP: do not append the image_header_t at the
669  		 * beginning of the file, but consume the space
670  		 * reserved for it.
671  		 */
672  
673  		if ((unsigned)sbuf.st_size < tparams->header_size) {
674  			fprintf (stderr,
675  				"%s: Bad size: \"%s\" is too small for XIP\n",
676  				params.cmdname, datafile);
677  			exit (EXIT_FAILURE);
678  		}
679  
680  		for (p = ptr; p < ptr + tparams->header_size; p++) {
681  			if ( *p != 0xff ) {
682  				fprintf (stderr,
683  					"%s: Bad file: \"%s\" has invalid buffer for XIP\n",
684  					params.cmdname, datafile);
685  				exit (EXIT_FAILURE);
686  			}
687  		}
688  
689  		offset = tparams->header_size;
690  	}
691  
692  	size = sbuf.st_size - offset;
693  	if (write(ifd, ptr + offset, size) != size) {
694  		fprintf (stderr, "%s: Write error on %s: %s\n",
695  			params.cmdname, params.imagefile, strerror(errno));
696  		exit (EXIT_FAILURE);
697  	}
698  
699  	tail = size % 4;
700  	if ((pad == 1) && (tail != 0)) {
701  
702  		if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
703  			fprintf (stderr, "%s: Write error on %s: %s\n",
704  				params.cmdname, params.imagefile,
705  				strerror(errno));
706  			exit (EXIT_FAILURE);
707  		}
708  	} else if (pad > 1) {
709  		while (pad > 0) {
710  			int todo = sizeof(zeros);
711  
712  			if (todo > pad)
713  				todo = pad;
714  			if (write(ifd, (char *)&zeros, todo) != todo) {
715  				fprintf(stderr, "%s: Write error on %s: %s\n",
716  					params.cmdname, params.imagefile,
717  					strerror(errno));
718  				exit(EXIT_FAILURE);
719  			}
720  			pad -= todo;
721  		}
722  	}
723  
724  	(void) munmap((void *)ptr, sbuf.st_size);
725  	(void) close (dfd);
726  }
727