svn commit: r272231 - in user/marcel/mkimg: . tests

Marcel Moolenaar marcel at FreeBSD.org
Sun Sep 28 00:20:12 UTC 2014


Author: marcel
Date: Sun Sep 28 00:20:08 2014
New Revision: 272231
URL: http://svnweb.freebsd.org/changeset/base/272231

Log:
  Sync with ^head/usr.bin/mkimg at 272217

Added:
  user/marcel/mkimg/qcow.c
     - copied unchanged from r272230, head/usr.bin/mkimg/qcow.c
  user/marcel/mkimg/tests/
     - copied from r272230, head/usr.bin/mkimg/tests/
Modified:
  user/marcel/mkimg/Makefile
  user/marcel/mkimg/apm.c
  user/marcel/mkimg/bsd.c
  user/marcel/mkimg/ebr.c
  user/marcel/mkimg/gpt.c
  user/marcel/mkimg/image.c
  user/marcel/mkimg/image.h
  user/marcel/mkimg/mbr.c
  user/marcel/mkimg/mkimg.1
  user/marcel/mkimg/mkimg.c
  user/marcel/mkimg/mkimg.h
  user/marcel/mkimg/pc98.c
  user/marcel/mkimg/scheme.c
  user/marcel/mkimg/scheme.h
  user/marcel/mkimg/vhd.c
  user/marcel/mkimg/vmdk.c
  user/marcel/mkimg/vtoc8.c
Directory Properties:
  user/marcel/mkimg/   (props changed)

Modified: user/marcel/mkimg/Makefile
==============================================================================
--- user/marcel/mkimg/Makefile	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/Makefile	Sun Sep 28 00:20:08 2014	(r272231)
@@ -1,13 +1,18 @@
 # $FreeBSD$
 
+.include <src.opts.mk>
+
 PROG=	mkimg
 SRCS=	format.c image.c mkimg.c scheme.c
 MAN=	mkimg.1
 
+MKIMG_VERSION=20140927
+CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION}
 CFLAGS+=-DSPARSE_WRITE
 
 # List of formats to support
 SRCS+= \
+	qcow.c \
 	raw.c \
 	vhd.c \
 	vmdk.c
@@ -29,4 +34,8 @@ LDADD=	-lutil
 
 WARNS?=	6
 
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
 .include <bsd.prog.mk>

Modified: user/marcel/mkimg/apm.c
==============================================================================
--- user/marcel/mkimg/apm.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/apm.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$");
 #include "mkimg.h"
 #include "scheme.h"
 
+#ifndef APM_ENT_TYPE_APPLE_BOOT
+#define	APM_ENT_TYPE_APPLE_BOOT		"Apple_Bootstrap"
+#endif
 #ifndef APM_ENT_TYPE_FREEBSD_NANDFS
 #define	APM_ENT_TYPE_FREEBSD_NANDFS	"FreeBSD-nandfs"
 #endif
@@ -54,13 +57,12 @@ static struct mkimg_alias apm_aliases[] 
     {	ALIAS_NONE, 0 }
 };
 
-static u_int
-apm_metadata(u_int where)
+static lba_t
+apm_metadata(u_int where, lba_t blk)
 {
-	u_int secs;
 
-	secs = (where == SCHEME_META_IMG_START) ? nparts + 2 : 0;
-	return (secs);
+	blk += (where == SCHEME_META_IMG_START) ? nparts + 2 : 0;
+	return (round_block(blk));
 }
 
 static int

Modified: user/marcel/mkimg/bsd.c
==============================================================================
--- user/marcel/mkimg/bsd.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/bsd.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -52,13 +52,17 @@ static struct mkimg_alias bsd_aliases[] 
     {	ALIAS_NONE, 0 }
 };
 
-static u_int
-bsd_metadata(u_int where)
+static lba_t
+bsd_metadata(u_int where, lba_t blk)
 {
-	u_int secs;
 
-	secs = BBSIZE / secsz;
-	return ((where == SCHEME_META_IMG_START) ? secs : 0);
+	if (where == SCHEME_META_IMG_START)
+		blk += BBSIZE / secsz;
+	else if (where == SCHEME_META_IMG_END)
+		blk = round_cylinder(blk);
+	else
+		blk = round_block(blk);
+	return (blk);
 }
 
 static int
@@ -68,7 +72,7 @@ bsd_write(lba_t imgsz, void *bootcode)
 	struct disklabel *d;
 	struct partition *dp;
 	struct part *part;
-	int error, n;
+	int bsdparts, error, n;
 	uint16_t checksum;
 
 	buf = malloc(BBSIZE);
@@ -76,16 +80,13 @@ bsd_write(lba_t imgsz, void *bootcode)
 		return (ENOMEM);
 	if (bootcode != NULL) {
 		memcpy(buf, bootcode, BBSIZE);
-		memset(buf + secsz, 0, secsz);
+		memset(buf + secsz, 0, sizeof(struct disklabel));
 	} else
 		memset(buf, 0, BBSIZE);
 
-	imgsz = (lba_t)ncyls * nheads * nsecs;
-	error = image_set_size(imgsz);
-	if (error) {
-		free(buf);
-		return (error);
-	}
+	bsdparts = nparts + 1;	/* Account for c partition */
+	if (bsdparts < MAXPARTITIONS)
+		bsdparts = MAXPARTITIONS;
 
 	d = (void *)(buf + secsz);
 	le32enc(&d->d_magic, DISKMAGIC);
@@ -97,7 +98,7 @@ bsd_write(lba_t imgsz, void *bootcode)
 	le32enc(&d->d_secperunit, imgsz);
 	le16enc(&d->d_rpm, 3600);
 	le32enc(&d->d_magic2, DISKMAGIC);
-	le16enc(&d->d_npartitions, (8 > nparts + 1) ? 8 : nparts + 1);
+	le16enc(&d->d_npartitions, bsdparts);
 	le32enc(&d->d_bbsize, BBSIZE);
 
 	dp = &d->d_partitions[RAW_PART];
@@ -107,12 +108,15 @@ bsd_write(lba_t imgsz, void *bootcode)
 		dp = &d->d_partitions[n];
 		le32enc(&dp->p_size, part->size);
 		le32enc(&dp->p_offset, part->block);
+		le32enc(&dp->p_fsize, 0);
 		dp->p_fstype = ALIAS_TYPE2INT(part->type);
+		dp->p_frag = 0;
+		le16enc(&dp->p_cpg, 0);
 	}
 
-	dp = &d->d_partitions[nparts + 1];
+	dp = &d->d_partitions[bsdparts];
 	checksum = 0;
-	for (p = buf; p < (u_char *)dp; p += 2)
+	for (p = (void *)d; p < (u_char *)dp; p += 2)
 		checksum ^= le16dec(p);
 	le16enc(&d->d_checksum, checksum);
 

Modified: user/marcel/mkimg/ebr.c
==============================================================================
--- user/marcel/mkimg/ebr.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/ebr.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -49,13 +49,12 @@ static struct mkimg_alias ebr_aliases[] 
     {	ALIAS_NONE, 0 }
 };
 
-static u_int
-ebr_metadata(u_int where)
+static lba_t
+ebr_metadata(u_int where, lba_t blk)
 {
-	u_int secs;
 
-	secs = (where == SCHEME_META_PART_BEFORE) ? nsecs : 0;
-	return (secs);
+	blk += (where == SCHEME_META_PART_BEFORE) ? 1 : 0;
+	return (round_track(blk));
 }
 
 static void

Modified: user/marcel/mkimg/gpt.c
==============================================================================
--- user/marcel/mkimg/gpt.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/gpt.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -153,17 +153,15 @@ gpt_tblsz(void)
 	return ((nparts + ents - 1) / ents);
 }
 
-static u_int
-gpt_metadata(u_int where)
+static lba_t
+gpt_metadata(u_int where, lba_t blk)
 {
-	u_int secs;
 
-	if (where != SCHEME_META_IMG_START && where != SCHEME_META_IMG_END)
-		return (0);
-
-	secs = gpt_tblsz();
-	secs += (where == SCHEME_META_IMG_START) ? 2 : 1;
-	return (secs);
+	if (where == SCHEME_META_IMG_START || where == SCHEME_META_IMG_END) {
+		blk += gpt_tblsz();
+		blk += (where == SCHEME_META_IMG_START) ? 2 : 1;
+	}
+	return (round_block(blk));
 }
 
 static int

Modified: user/marcel/mkimg/image.c
==============================================================================
--- user/marcel/mkimg/image.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/image.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -94,12 +94,19 @@ image_copyin(lba_t blk, int fd, uint64_t
 int
 image_copyout(int fd)
 {
-	off_t ofs;
 	int error;
 
 	error = image_copyout_region(fd, 0, image_size);
-	if (error)
-		return (error);
+	if (!error)
+		error = image_copyout_done(fd);
+	return (error);
+}
+
+int
+image_copyout_done(int fd)
+{
+	off_t ofs;
+	int error;
 
 	ofs = lseek(fd, 0L, SEEK_CUR);
 	if (ofs == -1)
@@ -148,6 +155,33 @@ image_copyout_region(int fd, lba_t blk, 
 	return (error);
 }
 
+int
+image_data(lba_t blk, lba_t size)
+{
+	char *buffer, *p;
+
+	blk *= secsz;
+	if (lseek(image_fd, blk, SEEK_SET) != blk)
+		return (1);
+
+	size *= secsz;
+	buffer = malloc(size);
+	if (buffer == NULL)
+		return (1);
+
+	if (read(image_fd, buffer, size) != (ssize_t)size) {
+		free(buffer);
+		return (1);
+	}
+
+	p = buffer;
+	while (size > 0 && *p == '\0')
+		size--, p++;
+
+	free(buffer);
+	return ((size == 0) ? 0 : 1);
+}
+
 lba_t
 image_get_size(void)
 {

Modified: user/marcel/mkimg/image.h
==============================================================================
--- user/marcel/mkimg/image.h	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/image.h	Sun Sep 28 00:20:08 2014	(r272231)
@@ -33,7 +33,9 @@ typedef int64_t lba_t;
 
 int image_copyin(lba_t blk, int fd, uint64_t *sizep);
 int image_copyout(int fd);
+int image_copyout_done(int fd);
 int image_copyout_region(int fd, lba_t blk, lba_t size);
+int image_data(lba_t blk, lba_t size);
 lba_t image_get_size(void);
 int image_init(void);
 int image_set_size(lba_t blk);

Modified: user/marcel/mkimg/mbr.c
==============================================================================
--- user/marcel/mkimg/mbr.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/mbr.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -50,13 +50,12 @@ static struct mkimg_alias mbr_aliases[] 
     {	ALIAS_NONE, 0 }		/* Keep last! */
 };
 
-static u_int
-mbr_metadata(u_int where)
+static lba_t
+mbr_metadata(u_int where, lba_t blk)
 {
-	u_int secs;
 
-	secs = (where == SCHEME_META_IMG_START) ? nsecs : 0;
-	return (secs);
+	blk += (where == SCHEME_META_IMG_START) ? 1 : 0;
+	return (round_track(blk));
 }
 
 static void

Modified: user/marcel/mkimg/mkimg.1
==============================================================================
--- user/marcel/mkimg/mkimg.1	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/mkimg.1	Sun Sep 28 00:20:08 2014	(r272231)
@@ -24,12 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 2, 2014
+.Dd September 27, 2014
 .Dt MKIMG 1
 .Os
 .Sh NAME
 .Nm mkimg
-.Nd "utility to make a disk image"
+.Nd "utility to make disk images"
 .Sh SYNOPSIS
 .Nm
 .Op Fl H Ar heads
@@ -40,9 +40,12 @@
 .Op Fl f Ar format
 .Op Fl o Ar outfile
 .Op Fl v
+.Op Fl y
 .Fl s Ar scheme
 .Fl p Ar partition
 .Op Fl p Ar partition ...
+.Nm
+.Ar --formats | --schemes | --version
 .Sh DESCRIPTION
 The
 .Nm
@@ -111,10 +114,42 @@ option increases the level of output tha
 .Nm
 utility prints.
 .Pp
-For a complete list of supported partitioning schemes or supported output
-format, or for a detailed description of how to specify partitions, run the
+The
+.Op Fl y
+option is used for testing purposes only and is not to be used in production.
+When present, the
+.Nm
+utility will generate predictable values for Universally Unique Identifiers
+(UUIDs) and time stamps so that consecutive runs of the
+.Nm
+utility will create images that are identical.
+.Pp
+A set of long options exist to query about the
+.Nm
+utilty itself.
+Options in this set should be given by themselves because the
+.Nm
+utility exits immediately after providing the requested information.
+The version of the
+.Nm
+utility is printed when the
+.Ar --version
+option is given.
+The list of supported output formats is printed when the
+.Ar --formats
+option is given and the list of supported partitioning schemes is printed
+when the
+.Ar --schemes
+option is given.
+Both the format and scheme lists a space-separated lists for easy handling
+in scripts.
+.Pp
+For a more descriptive list of supported partitioning schemes or supported
+output format, or for a detailed description of how to specify partitions,
+run the
 .Nm
 utility without any arguments.
+This will print a usage message with all the necessary details.
 .Sh ENVIRONMENT
 .Bl -tag -width "TMPDIR" -compact
 .It Ev TMPDIR
@@ -160,6 +195,25 @@ utility as follows:
 .Dl % mkimg -s mbr -b /boot/mbr -p freebsd:-'mkimg -s bsd -b /boot/boot \
 -p freebsd-ufs:=root-file-system.ufs -p freebsd-swap::1G' -o mbr-bsd.img
 .Pp
+To accomodate the need to have partitions named or numbered in a certain
+way, the
+.Nm
+utility allows for the specification of empty partitions.
+For example, to create an image that is compatible with partition layouts
+found in
+.Pa /etc/disktab ,
+the 'd' partition often needs to be skipped.
+This is accomplished by inserting an unused partition after the first 2
+partition specifications.
+It is worth noting at this time that the BSD scheme will automatically
+skip the 'c' partition by virtue of it referring to the entire disk.
+To create an image that is compatible with the qp120at disk, use the
+.Nm
+utility as follows:
+.Dl % mkimg -s bsd -b /boot/boot -p freebsd-ufs:=root-file-system.ufs \
+-p freebsd-swap::20M -p- -p- -p- -p- -p freebsd-ufs:=usr-file-system.ufs \
+-o bsd.img
+.Pp
 For partitioning schemes that feature partition labels, the
 .Nm
 utility supports assigning labels to the partitions specified.

Modified: user/marcel/mkimg/mkimg.c
==============================================================================
--- user/marcel/mkimg/mkimg.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/mkimg.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <errno.h>
 #include <err.h>
 #include <fcntl.h>
+#include <getopt.h>
 #include <libutil.h>
 #include <limits.h>
 #include <stdio.h>
@@ -48,6 +49,17 @@ __FBSDID("$FreeBSD$");
 #include "mkimg.h"
 #include "scheme.h"
 
+#define	LONGOPT_FORMATS	0x01000001
+#define	LONGOPT_SCHEMES	0x01000002
+#define	LONGOPT_VERSION	0x01000003
+
+static struct option longopts[] = {
+	{ "formats", no_argument, NULL, LONGOPT_FORMATS },
+	{ "schemes", no_argument, NULL, LONGOPT_SCHEMES },
+	{ "version", no_argument, NULL, LONGOPT_VERSION },
+	{ NULL, 0, NULL, 0 }
+};
+
 struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist);
 u_int nparts = 0;
 
@@ -61,44 +73,103 @@ u_int secsz = 512;
 u_int blksz = 0;
 
 static void
-usage(const char *why)
+print_formats(int usage)
 {
 	struct mkimg_format *f, **f_iter;
+	const char *sep;
+
+	if (usage) {
+		fprintf(stderr, "    formats:\n");
+		SET_FOREACH(f_iter, formats) {
+			f = *f_iter;
+			fprintf(stderr, "\t%s\t-  %s\n", f->name,
+			    f->description);
+		}
+	} else {
+		sep = "";
+		SET_FOREACH(f_iter, formats) {
+			f = *f_iter;
+			printf("%s%s", sep, f->name);
+			sep = " ";
+		}
+		putchar('\n');
+	}
+}
+
+static void
+print_schemes(int usage)
+{
 	struct mkimg_scheme *s, **s_iter;
+	const char *sep;
+
+	if (usage) {
+		fprintf(stderr, "    schemes:\n");
+		SET_FOREACH(s_iter, schemes) {
+			s = *s_iter;
+			fprintf(stderr, "\t%s\t-  %s\n", s->name,
+			    s->description);
+		}
+	} else {
+		sep = "";
+		SET_FOREACH(s_iter, schemes) {
+			s = *s_iter;
+			printf("%s%s", sep, s->name);
+			sep = " ";
+		}
+		putchar('\n');
+	}
+}
+
+static void
+print_version(void)
+{
+	u_int width;
+
+#ifdef __LP64__
+	width = 64;
+#else
+	width = 32;
+#endif
+	printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width);
+}
+
+static void
+usage(const char *why)
+{
 
 	warnx("error: %s", why);
-	fprintf(stderr, "\nusage: %s <options>\n", getprogname());
+	fputc('\n', stderr);
+	fprintf(stderr, "usage: %s <options>\n", getprogname());
 
 	fprintf(stderr, "    options:\n");
+	fprintf(stderr, "\t--formats\t-  list image formats\n");
+	fprintf(stderr, "\t--schemes\t-  list partition schemes\n");
+	fprintf(stderr, "\t--version\t-  show version information\n");
+	fputc('\n', stderr);
 	fprintf(stderr, "\t-b <file>\t-  file containing boot code\n");
 	fprintf(stderr, "\t-f <format>\n");
 	fprintf(stderr, "\t-o <file>\t-  file to write image into\n");
 	fprintf(stderr, "\t-p <partition>\n");
 	fprintf(stderr, "\t-s <scheme>\n");
+	fprintf(stderr, "\t-v\t\t-  increase verbosity\n");
+	fprintf(stderr, "\t-y\t\t-  [developers] enable unit test\n");
 	fprintf(stderr, "\t-H <num>\t-  number of heads to simulate\n");
 	fprintf(stderr, "\t-P <num>\t-  physical sector size\n");
 	fprintf(stderr, "\t-S <num>\t-  logical sector size\n");
 	fprintf(stderr, "\t-T <num>\t-  number of tracks to simulate\n");
-
-	fprintf(stderr, "\n    formats:\n");
-	SET_FOREACH(f_iter, formats) {
-		f = *f_iter;
-		fprintf(stderr, "\t%s\t-  %s\n", f->name, f->description);
-	}
-
-	fprintf(stderr, "\n    schemes:\n");
-	SET_FOREACH(s_iter, schemes) {
-		s = *s_iter;
-		fprintf(stderr, "\t%s\t-  %s\n", s->name, s->description);
-	}
-
-	fprintf(stderr, "\n    partition specification:\n");
+	fputc('\n', stderr);
+	print_formats(1);
+	fputc('\n', stderr);
+	print_schemes(1);
+	fputc('\n', stderr);
+	fprintf(stderr, "    partition specification:\n");
 	fprintf(stderr, "\t<t>[/<l>]::<size>\t-  empty partition of given "
 	    "size\n");
 	fprintf(stderr, "\t<t>[/<l>]:=<file>\t-  partition content and size "
 	    "are determined\n\t\t\t\t   by the named file\n");
 	fprintf(stderr, "\t<t>[/<l>]:-<cmd>\t-  partition content and size "
 	    "are taken from\n\t\t\t\t   the output of the command to run\n");
+	fprintf(stderr, "\t-\t\t\t-  unused partition entry\n");
 	fprintf(stderr, "\t    where:\n");
 	fprintf(stderr, "\t\t<t>\t-  scheme neutral partition type\n");
 	fprintf(stderr, "\t\t<l>\t-  optional scheme-dependent partition "
@@ -138,6 +209,9 @@ pwr_of_two(u_int nr)
  *		  '-'   contents holds a command to run; the output of
  *			which is the contents of the partition.
  *	contents  the specification of a partition's contents
+ *
+ * A specification that is a single dash indicates an unused partition
+ * entry.
  */
 static int
 parse_part(const char *spec)
@@ -147,6 +221,11 @@ parse_part(const char *spec)
 	size_t len;
 	int error;
 
+	if (strcmp(spec, "-") == 0) {
+		nparts++;
+		return (0);
+	}
+
 	part = calloc(1, sizeof(struct part));
 	if (part == NULL)
 		return (ENOMEM);
@@ -355,7 +434,8 @@ main(int argc, char *argv[])
 
 	bcfd = -1;
 	outfd = 1;	/* Write to stdout by default */
-	while ((c = getopt(argc, argv, "b:f:o:p:s:vyH:P:S:T:")) != -1) {
+	while ((c = getopt_long(argc, argv, "b:f:o:p:s:vyH:P:S:T:",
+	    longopts, NULL)) != -1) {
 		switch (c) {
 		case 'b':	/* BOOT CODE */
 			if (bcfd != -1)
@@ -421,6 +501,18 @@ main(int argc, char *argv[])
 			if (error)
 				errc(EX_DATAERR, error, "track size");
 			break;
+		case LONGOPT_FORMATS:
+			print_formats(0);
+			exit(EX_OK);
+			/*NOTREACHED*/
+		case LONGOPT_SCHEMES:
+			print_schemes(0);
+			exit(EX_OK);
+			/*NOTREACHED*/
+		case LONGOPT_VERSION:
+			print_version();
+			exit(EX_OK);
+			/*NOTREACHED*/
 		default:
 			usage("unknown option");
 		}

Modified: user/marcel/mkimg/mkimg.h
==============================================================================
--- user/marcel/mkimg/mkimg.h	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/mkimg.h	Sun Sep 28 00:20:08 2014	(r272231)
@@ -66,6 +66,21 @@ round_block(lba_t n)
 	return ((n + b - 1) & ~(b - 1));
 }
 
+static inline lba_t
+round_cylinder(lba_t n)
+{
+	u_int cyl = nsecs * nheads;
+	u_int r = n % cyl;
+	return ((r == 0) ? n : n + cyl - r);
+}
+
+static inline lba_t
+round_track(lba_t n)
+{
+	u_int r = n % nsecs;
+	return ((r == 0) ? n : n + nsecs - r);
+}
+
 #if !defined(SPARSE_WRITE)
 #define	sparse_write	write
 #else

Modified: user/marcel/mkimg/pc98.c
==============================================================================
--- user/marcel/mkimg/pc98.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/pc98.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -59,13 +59,12 @@ static struct mkimg_alias pc98_aliases[]
     {	ALIAS_NONE, 0 }
 };
 
-static u_int
-pc98_metadata(u_int where)
+static lba_t
+pc98_metadata(u_int where, lba_t blk)
 {
-	u_int secs;
-
-	secs = PC98_BOOTCODESZ / secsz;
-	return ((where == SCHEME_META_IMG_START) ? secs : 0);
+	if (where == SCHEME_META_IMG_START)
+		blk += PC98_BOOTCODESZ / secsz;
+	return (round_track(blk));
 }
 
 static void

Copied: user/marcel/mkimg/qcow.c (from r272230, head/usr.bin/mkimg/qcow.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/marcel/mkimg/qcow.c	Sun Sep 28 00:20:08 2014	(r272231, copy of r272230, head/usr.bin/mkimg/qcow.c)
@@ -0,0 +1,369 @@
+/*-
+ * Copyright (c) 2014 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "image.h"
+#include "format.h"
+#include "mkimg.h"
+
+/* Default cluster sizes. */
+#define	QCOW1_CLSTR_LOG2SZ	12	/* 4KB */
+#define	QCOW2_CLSTR_LOG2SZ	16	/* 64KB */
+
+/* Flag bits in cluster offsets */
+#define	QCOW_CLSTR_COMPRESSED	(1ULL << 62)
+#define	QCOW_CLSTR_COPIED	(1ULL << 63)
+
+struct qcow_header {
+	uint32_t	magic;
+#define	QCOW_MAGIC		0x514649fb
+	uint32_t	version;
+#define	QCOW_VERSION_1		1
+#define	QCOW_VERSION_2		2
+	uint64_t	path_offset;
+	uint32_t	path_length;
+	uint32_t	clstr_log2sz;	/* v2 only */
+	uint64_t	disk_size;
+	union {
+		struct {
+			uint8_t		clstr_log2sz;
+			uint8_t		l2_log2sz;
+			uint16_t	_pad;
+			uint32_t	encryption;
+			uint64_t	l1_offset;
+		} v1;
+		struct {
+			uint32_t	encryption;
+			uint32_t	l1_entries;
+			uint64_t	l1_offset;
+			uint64_t	refcnt_offset;
+			uint32_t	refcnt_entries;
+			uint32_t	snapshot_count;
+			uint64_t	snapshot_offset;
+		} v2;
+	} u;
+};
+
+static u_int clstr_log2sz;
+
+static uint64_t
+round_clstr(uint64_t ofs)
+{
+	uint64_t clstrsz;
+
+	clstrsz = 1UL << clstr_log2sz;
+	return ((ofs + clstrsz - 1) & ~(clstrsz - 1));
+}
+
+static int
+qcow_resize(lba_t imgsz, u_int version)
+{
+	uint64_t imagesz;
+
+	switch (version) {
+	case QCOW_VERSION_1:
+		clstr_log2sz = QCOW1_CLSTR_LOG2SZ;
+		break;
+	case QCOW_VERSION_2:
+		clstr_log2sz = QCOW2_CLSTR_LOG2SZ;
+		break;
+	default:
+		return (EDOOFUS);
+	}
+
+	imagesz = round_clstr(imgsz * secsz);
+
+	if (verbose)
+		fprintf(stderr, "QCOW: image size = %ju, cluster size = %u\n",
+		    (uintmax_t)imagesz, (u_int)(1U << clstr_log2sz));
+
+	return (image_set_size(imagesz / secsz));
+}
+
+static int
+qcow1_resize(lba_t imgsz)
+{
+
+	return (qcow_resize(imgsz, QCOW_VERSION_1));
+}
+
+static int
+qcow2_resize(lba_t imgsz)
+{
+
+	return (qcow_resize(imgsz, QCOW_VERSION_2));
+}
+
+static int
+qcow_write(int fd, u_int version)
+{
+	struct qcow_header *hdr;
+	uint64_t *l1tbl, *l2tbl, *rctbl;
+	uint16_t *rcblk;
+	uint64_t clstr_imgsz, clstr_l2tbls, clstr_l1tblsz;
+	uint64_t clstr_rcblks, clstr_rctblsz;
+	uint64_t n, imagesz, nclstrs, ofs, ofsflags;
+	lba_t blk, blkofs, blk_imgsz;
+	u_int l1clno, l2clno, rcclno;
+	u_int blk_clstrsz;
+	u_int clstrsz, l1idx, l2idx;
+	int error;
+
+	if (clstr_log2sz == 0)
+		return (EDOOFUS);
+
+	clstrsz = 1U << clstr_log2sz;
+	blk_clstrsz = clstrsz / secsz;
+	blk_imgsz = image_get_size();
+	imagesz = blk_imgsz * secsz;
+	clstr_imgsz = imagesz >> clstr_log2sz;
+	clstr_l2tbls = round_clstr(clstr_imgsz * 8) >> clstr_log2sz;
+	clstr_l1tblsz = round_clstr(clstr_l2tbls * 8) >> clstr_log2sz;
+	nclstrs = clstr_imgsz + clstr_l2tbls + clstr_l1tblsz + 1;
+	clstr_rcblks = clstr_rctblsz = 0;
+	do {
+		n = clstr_rcblks + clstr_rctblsz;
+		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
+		clstr_rctblsz = round_clstr(clstr_rcblks * 8) >> clstr_log2sz;
+	} while (n < (clstr_rcblks + clstr_rctblsz));
+
+	/*
+	 * We got all the sizes in clusters. Start the layout.
+	 * 0 - header
+	 * 1 - L1 table
+	 * 2 - RC table (v2 only)
+	 * 3 - L2 tables
+	 * 4 - RC block (v2 only)
+	 * 5 - data
+	 */
+
+	l1clno = 1;
+	rcclno = 0;
+	rctbl = l2tbl = l1tbl = NULL;
+	rcblk = NULL;
+
+	hdr = calloc(1, clstrsz);
+	if (hdr == NULL)
+		return (errno);
+
+	be32enc(&hdr->magic, QCOW_MAGIC);
+	be32enc(&hdr->version, version);
+	be64enc(&hdr->disk_size, imagesz);
+	switch (version) {
+	case QCOW_VERSION_1:
+		ofsflags = 0;
+		l2clno = l1clno + clstr_l1tblsz;
+		hdr->u.v1.clstr_log2sz = clstr_log2sz;
+		hdr->u.v1.l2_log2sz = clstr_log2sz - 3;
+		be64enc(&hdr->u.v1.l1_offset, clstrsz * l1clno);
+		break;
+	case QCOW_VERSION_2:
+		ofsflags = QCOW_CLSTR_COPIED;
+		rcclno = l1clno + clstr_l1tblsz;
+		l2clno = rcclno + clstr_rctblsz;
+		be32enc(&hdr->clstr_log2sz, clstr_log2sz);
+		be32enc(&hdr->u.v2.l1_entries, clstr_l2tbls);
+		be64enc(&hdr->u.v2.l1_offset, clstrsz * l1clno);
+		be64enc(&hdr->u.v2.refcnt_offset, clstrsz * rcclno);
+		be32enc(&hdr->u.v2.refcnt_entries, clstr_rcblks);
+		break;
+	default:
+		return (EDOOFUS);
+	}
+
+	if (sparse_write(fd, hdr, clstrsz) < 0) {
+                error = errno;
+		goto out;
+	}
+
+	free(hdr);
+	hdr = NULL;
+
+	ofs = clstrsz * l2clno;
+	nclstrs = 1 + clstr_l1tblsz + clstr_rctblsz;
+
+	l1tbl = calloc(1, clstrsz * clstr_l1tblsz);
+	if (l1tbl == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	for (n = 0; n < clstr_imgsz; n++) {
+		blk = n * blk_clstrsz;
+		if (image_data(blk, blk_clstrsz)) {
+			nclstrs++;
+			l1idx = n >> (clstr_log2sz - 3);
+			if (l1tbl[l1idx] == 0) {
+				be64enc(l1tbl + l1idx, ofs + ofsflags);
+				ofs += clstrsz;
+				nclstrs++;
+			}
+		}
+	}
+
+	if (sparse_write(fd, l1tbl, clstrsz * clstr_l1tblsz) < 0) {
+		error = errno;
+		goto out;
+	}
+
+	clstr_rcblks = 0;
+	do {
+		n = clstr_rcblks;
+		clstr_rcblks = round_clstr((nclstrs + n) * 2) >> clstr_log2sz;
+	} while (n < clstr_rcblks);
+
+	if (rcclno > 0) {
+		rctbl = calloc(1, clstrsz * clstr_rctblsz);
+		if (rctbl == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+		for (n = 0; n < clstr_rcblks; n++) {
+			be64enc(rctbl + n, ofs);
+			ofs += clstrsz;
+			nclstrs++;
+		}
+		if (sparse_write(fd, rctbl, clstrsz * clstr_rctblsz) < 0) {
+			error = errno;
+			goto out;
+		}
+		free(rctbl);
+		rctbl = NULL;
+	}
+
+	l2tbl = malloc(clstrsz);
+	if (l2tbl == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	for (l1idx = 0; l1idx < clstr_l2tbls; l1idx++) {
+		if (l1tbl[l1idx] == 0)
+			continue;
+		memset(l2tbl, 0, clstrsz);
+		blkofs = (lba_t)l1idx * blk_clstrsz * (clstrsz >> 3);
+		for (l2idx = 0; l2idx < (clstrsz >> 3); l2idx++) {
+			blk = blkofs + (lba_t)l2idx * blk_clstrsz;
+			if (blk >= blk_imgsz)
+				break;
+			if (image_data(blk, blk_clstrsz)) {
+				be64enc(l2tbl + l2idx, ofs + ofsflags);
+				ofs += clstrsz;
+			}
+		}
+		if (sparse_write(fd, l2tbl, clstrsz) < 0) {
+			error = errno;
+			goto out;
+		}
+	}
+
+	free(l2tbl);
+	l2tbl = NULL;
+	free(l1tbl);
+	l1tbl = NULL;
+
+	if (rcclno > 0) {
+		rcblk = calloc(1, clstrsz * clstr_rcblks);
+		if (rcblk == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+		for (n = 0; n < nclstrs; n++)
+			be16enc(rcblk + n, 1);
+		if (sparse_write(fd, rcblk, clstrsz * clstr_rcblks) < 0) {
+			error = errno;
+			goto out;
+		}
+		free(rcblk);
+		rcblk = NULL;
+	}
+
+	error = 0;
+	for (n = 0; n < clstr_imgsz; n++) {
+		blk = n * blk_clstrsz;
+		if (image_data(blk, blk_clstrsz)) {
+			error = image_copyout_region(fd, blk, blk_clstrsz);
+			if (error)
+				break;
+		}
+	}
+	if (!error)
+		error = image_copyout_done(fd);
+
+ out:
+	if (rcblk != NULL)
+		free(rcblk);
+	if (l2tbl != NULL)
+		free(l2tbl);
+	if (rctbl != NULL)
+		free(rctbl);
+	if (l1tbl != NULL)
+		free(l1tbl);
+	if (hdr != NULL)
+		free(hdr);
+	return (error);
+}
+
+static int
+qcow1_write(int fd)
+{
+
+	return (qcow_write(fd, QCOW_VERSION_1));
+}
+
+static int
+qcow2_write(int fd)
+{
+
+	return (qcow_write(fd, QCOW_VERSION_2));
+}
+
+static struct mkimg_format qcow1_format = {
+	.name = "qcow",
+	.description = "QEMU Copy-On-Write, version 1",
+	.resize = qcow1_resize,
+	.write = qcow1_write,
+};
+FORMAT_DEFINE(qcow1_format);
+
+static struct mkimg_format qcow2_format = {
+	.name = "qcow2",
+	.description = "QEMU Copy-On-Write, version 2",
+	.resize = qcow2_resize,
+	.write = qcow2_write,
+};
+FORMAT_DEFINE(qcow2_format);

Modified: user/marcel/mkimg/scheme.c
==============================================================================
--- user/marcel/mkimg/scheme.c	Sat Sep 27 23:57:21 2014	(r272230)
+++ user/marcel/mkimg/scheme.c	Sun Sep 28 00:20:08 2014	(r272231)
@@ -171,10 +171,8 @@ scheme_max_secsz(void)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list