kern/84634: Utility to control GEOM uzip class and some patches

Stanislav Sedov stas at 310.ru
Sun Aug 7 05:20:08 GMT 2005


>Number:         84634
>Category:       kern
>Synopsis:       Utility to control GEOM uzip class and some patches
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Aug 07 05:20:06 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Stanislav Sedov
>Release:        FreeBSD 7.0-CURRENT i386
>Organization:
310.ru [Tridesyatoe]
>Environment:
System: FreeBSD stalingrad.realnet 7.0-CURRENT FreeBSD 7.0-CURRENT #96: Thu Jul 28 21:05:39 UTC 2005 root at stalingrad.realnet:/work/src/fbsd-cur/src/sys/i386/compile/DESKTOP i386


	
>Description:
	It's utility to control behavour of GEOM uzip class and for creating/
extracting uzip images. Since we doesn't need now to support strange CLOOP format, i've modified it slightly. Also there's some patches to manipulate class uzing guzip utility and some bugfixes, e.g deny writing to this device through g_acess(this prevents geom_vfs from errors).

>How-To-Repeat:
	
>Fix:

	

--- 1.diff begins here ---
--- sys/geom/uzip/g_uzip.c.orig	Tue Jul 19 09:01:32 2005
+++ sys/geom/uzip/g_uzip.c	Sun Aug  7 10:59:24 2005
@@ -1,4 +1,5 @@
 /*-
+ * Copyright (c) 2005 Stanislav Sedov
  * Copyright (c) 2004 Max Khon
  * All rights reserved.
  *
@@ -58,18 +59,21 @@
 
 /*
  * Integer values (block size, number of blocks, offsets)
- * are stored in big-endian (network) order on disk and struct cloop_header
+ * are stored in big-endian (network) order on disk and struct g_uzip_header
  * and in native order in struct g_uzip_softc
  */
 
-#define CLOOP_MAGIC_LEN 128
-static char CLOOP_MAGIC_START[] = "#!/bin/sh\n";
+#define GUZIP_MAGIC_LEN 20
+static char GUZIP_MAGIC[] = "<FreeBSD-GEOM-UZIP>";
 
-struct cloop_header {
-	char magic[CLOOP_MAGIC_LEN];	/* cloop magic */
+/* Size of header must be multiple of 8 */
+typedef struct g_uzip_header {
+	char magic[GUZIP_MAGIC_LEN];	/* g_uzip magic */
+	uint32_t lorder;		/* byte order */
+	uint64_t fsize;			/* original size */
 	uint32_t blksz;			/* block size */
 	uint32_t nblocks;		/* number of blocks */
-};
+} g_uzip_header_t;
 
 struct g_uzip_softc {
 	uint32_t blksz;			/* block size */
@@ -87,9 +91,10 @@
 g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp)
 {
 	if (gp != NULL) {
-		printf("%s: %d requests, %d cached\n",
-		    gp->name, sc->req_total, sc->req_cached);
+		DPRINTF(("%s: %d requests, %d cached\n",
+		    gp->name, sc->req_total, sc->req_cached));
 	}
+	KASSERT(sc != NULL, ("geom_uzip: NULL sc in free"));
 	if (sc->offsets != NULL)
 		free(sc->offsets, M_GEOM_UZIP);
 	mtx_destroy(&sc->last_mtx);
@@ -171,14 +176,16 @@
 		if (err != Z_STREAM_END) {
 			sc->last_blk = -1;
 			mtx_unlock(&sc->last_mtx);
-			DPRINTF(("%s: done: inflate failed (%lld + %lld -> %lld + %lld + %lld)\n",
+			DPRINTF(("%s: done: inflate failed (%lld + %lld"\
+			    " -> %lld + %lld + %lld)\n",
 			    gp->name, pos, len, uoff, upos, ulen));
 			inflateEnd(&zs);
 			bp2->bio_error = EIO;
 			goto done;
 		}
 		sc->last_blk = i;
-		DPRINTF(("%s: done: inflated %lld + %lld -> %lld + %lld + %lld\n",
+		DPRINTF(("%s: done: inflated %lld + %lld -> %lld + %lld + "\
+		    "%lld\n",
 		    gp->name,
 		    pos, len,
 		    uoff, upos, ulen));
@@ -257,7 +264,8 @@
 			sc->req_cached++;
 			mtx_unlock(&sc->last_mtx);
 
-			DPRINTF(("%s: start: cached 0 + %lld, %lld + 0 + %lld\n",
+			DPRINTF(("%s: start: cached 0 + %lld, %lld + 0 +"
+			    " %lld\n",
 			    gp->name, bp->bio_length, uoff, bp->bio_length));
 			bp->bio_completed = bp->bio_length;
 			g_io_deliver(bp, 0);
@@ -277,13 +285,15 @@
 	    pp->name, pp->sectorsize, pp->mediasize,
 	    pp2->name, pp2->sectorsize, pp2->mediasize));
 	bsize = pp2->sectorsize;
-	bp2->bio_offset = sc->offsets[start_blk] - sc->offsets[start_blk] % bsize;
+	bp2->bio_offset = sc->offsets[start_blk] - sc->offsets[start_blk] % \
+	    bsize;
 	bp2->bio_length = sc->offsets[end_blk] - bp2->bio_offset;
 	bp2->bio_length = (bp2->bio_length + bsize - 1) / bsize * bsize;
 	DPRINTF(("%s: start %lld + %lld -> %lld + %lld -> %lld + %lld\n",
 	    gp->name,
 	    bp->bio_offset, bp->bio_length,
-	    sc->offsets[start_blk], sc->offsets[end_blk] - sc->offsets[start_blk],
+	    sc->offsets[start_blk], sc->offsets[end_blk] -
+	    sc->offsets[start_blk],
 	    bp2->bio_offset, bp2->bio_length));
 	bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UZIP, M_NOWAIT);
 	if (bp2->bio_data == NULL) {
@@ -295,20 +305,42 @@
 	DPRINTF(("%s: start ok\n", gp->name));
 }
 
+static int
+g_uzip_destroy(struct g_geom *gp, boolean_t force)
+{
+	struct g_provider *pp;
+
+	g_trace(G_T_TOPOLOGY, "g_uzip_destroy(%s)", gp->name);
+	g_topology_assert();
+	
+	if (gp->softc == NULL)
+		return ENXIO;
+
+	pp = LIST_FIRST(&gp->provider);
+	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
+		DPRINTF(("Provider %s is still open, so it "
+		    "can't be definitely removed.\n", pp->name));
+		if (force == 0)
+			return (EBUSY);
+        } 
+
+	g_uzip_softc_free(gp->softc, gp);
+	gp->softc = NULL;
+	g_wither_geom(gp, ENXIO);
+
+	return (0);
+}
+
 static void
 g_uzip_orphan(struct g_consumer *cp)
 {
-	struct g_geom *gp;
 
 	g_trace(G_T_TOPOLOGY, "g_uzip_orphan(%p/%s)", cp, cp->provider->name);
 	g_topology_assert();
 	KASSERT(cp->provider->error != 0,
 		("g_uzip_orphan with error == 0"));
 
-	gp = cp->geom;
-	g_uzip_softc_free(gp->softc, gp);
-	gp->softc = NULL;
-	g_wither_geom(gp, cp->provider->error);
+	g_uzip_destroy(cp->geom, 1);
 }
 
 static int
@@ -318,9 +350,16 @@
 	struct g_consumer *cp;
 
 	gp = pp->geom;
+	DPRINTF(("%s: g_uzip_access, dr = %d, dw = %d, de = %d\n", \
+	    gp->name, dr, dw, de));
+
 	cp = LIST_FIRST(&gp->consumer);
 	KASSERT (cp != NULL, ("g_uzip_access but no consumer"));
 
+	/* Deny writing */
+	if (cp->acw + dw > 0)
+		return ENXIO;
+
 	return (g_access(cp, dr, dw, de));
 }
 
@@ -333,18 +372,17 @@
 	g_trace(G_T_TOPOLOGY, "g_uzip_spoiled(%p/%s)", cp, gp->name);
 	g_topology_assert();
 
-	g_uzip_softc_free(gp->softc, gp);
-	gp->softc = NULL;
-	g_wither_geom(gp, ENXIO);
+	g_uzip_destroy(gp, 1);
 }
 
 static struct g_geom *
-g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
+g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
 {
 	int error;
-	uint32_t i, total_offsets, offsets_read, blk;
+	uint32_t i, offsets_read, blk;
 	void *buf;
-	struct cloop_header *header;
+	int lorder;
+	struct g_uzip_header *header;
 	struct g_consumer *cp;
 	struct g_geom *gp;
 	struct g_provider *pp2;
@@ -371,7 +409,7 @@
 	g_topology_unlock();
 
 	/*
-	 * Read cloop header, look for CLOOP magic, perform
+	 * Read g_uzip header, look for magic, perform
 	 * other validity checks.
 	 */
 	DPRINTF(("%s: media sectorsize %u, mediasize %lld\n",
@@ -379,14 +417,10 @@
 	buf = g_read_data(cp, 0, pp->sectorsize, &error);
 	if (buf == NULL || error != 0)
 		goto err;
-	header = (struct cloop_header *) buf;
-	if (strncmp(header->magic, CLOOP_MAGIC_START,
-		    sizeof(CLOOP_MAGIC_START) - 1) != 0) {
-		DPRINTF(("%s: no CLOOP magic\n", gp->name));
-		goto err;
-	}
-	if (header->magic[0x0b] != 'V' || header->magic[0x0c] < '2') {
-		DPRINTF(("%s: image version too old\n", gp->name));
+	header = (struct g_uzip_header *) buf;
+	if (bcmp(header->magic, GUZIP_MAGIC,
+		GUZIP_MAGIC_LEN) != 0) {
+		DPRINTF(("%s: no g_uzip magic\n", gp->name));
 		goto err;
 	}
 
@@ -397,6 +431,7 @@
 	gp->softc = sc;
 	sc->blksz = ntohl(header->blksz);
 	sc->nblocks = ntohl(header->nblocks);
+	lorder = ntohl(header->lorder);
 	if (sc->blksz % 512 != 0) {
 		printf("%s: block size (%u) should be multiple of 512.\n",
 		    gp->name, sc->blksz);
@@ -405,23 +440,35 @@
 	if (sc->blksz > MAX_BLKSZ) {
 		printf("%s: block size (%u) should not be larger than %d.\n",
 		    gp->name, sc->blksz, MAX_BLKSZ);
+		goto err;
 	}
-	total_offsets = sc->nblocks + 1;
-	if (sizeof(struct cloop_header) +
-	    total_offsets * sizeof(uint64_t) > pp->mediasize) {
+
+	/* Check if offsets table can exist on media */
+	if ((pp->sectorsize - sizeof(g_uzip_header_t)) % 8 != 0) {
+		DPRINTF(("%s: GEOM uzip image can't exist on this"
+		    "type of media\n", gp->name));
+		goto err;
+	}
+
+	if (sizeof(g_uzip_header_t) +
+	    sc->nblocks * sizeof(uint64_t) > pp->mediasize) {
 		printf("%s: media too small for %u blocks\n",
 		       gp->name, sc->nblocks);
 		goto err;
 	}
 	sc->offsets = malloc(
-	    total_offsets * sizeof(uint64_t), M_GEOM_UZIP, M_WAITOK);
-	offsets_read = MIN(total_offsets,
-	    (pp->sectorsize - sizeof(*header)) / sizeof(uint64_t));
+	    (sc->nblocks + 1) * sizeof(uint64_t), M_GEOM_UZIP, M_WAITOK);
+	offsets_read = MIN(sc->nblocks,
+	    (pp->sectorsize - sizeof(g_uzip_header_t)) / sizeof(uint64_t));
+
+	/* Fill first offset */
+	sc->offsets[0] = sizeof(*header) + sc->nblocks * sizeof(uint64_t);
+
 	for (i = 0; i < offsets_read; i++)
-		sc->offsets[i] = be64toh(((uint64_t *) (header + 1))[i]);
+		sc->offsets[i + 1] = ((uint64_t *) (header + 1))[i];
 	DPRINTF(("%s: %u offsets in the first sector\n",
 	       gp->name, offsets_read));
-	for (blk = 1; offsets_read < total_offsets; blk++) {
+	for (blk = 1; offsets_read < sc->nblocks; blk++) {
 		uint32_t nread;
 
 		free(buf, M_GEOM);
@@ -429,16 +476,41 @@
 		    cp, blk * pp->sectorsize, pp->sectorsize, &error);
 		if (buf == NULL || error != 0)
 			goto err;
-		nread = MIN(total_offsets - offsets_read,
+		nread = MIN(sc->nblocks - offsets_read,
 		     pp->sectorsize / sizeof(uint64_t));
 		DPRINTF(("%s: %u offsets read from sector %d\n",
 		    gp->name, nread, blk));
 		for (i = 0; i < nread; i++) {
-			sc->offsets[offsets_read + i] =
-			    be64toh(((uint64_t *) buf)[i]);
+			sc->offsets[offsets_read + i + 1] =
+			    ((uint64_t *) buf)[i];
 		}
 		offsets_read += nread;
 	}
+	if (lorder != BYTE_ORDER && BYTE_ORDER == LITTLE_ENDIAN) {
+		DPRINTF(("%s: image in big endian, "\
+		    "converting offsets to little endian\n", gp->name));
+		for (i = 1; i <= sc->nblocks; i++)
+			sc->offsets[i] = be64toh(sc->offsets[i]);
+	}
+	else if (lorder != BYTE_ORDER && BYTE_ORDER == BIG_ENDIAN) {
+		DPRINTF(("%s: image in little endian, "\
+		    "converting offsets to big endian\n", gp->name));
+		for (i = 1; i <= sc->nblocks; i++)
+			sc->offsets[i] = le64toh(sc->offsets[i]);
+	}
+
+	/* Preform offsets correctness checking */
+	for (i = 1; i <= sc->nblocks; i++)
+		if (sc->offsets[i] - sc->offsets[i - 1] <= 0) {
+			DPRINTF(("%s: incorrect offsets table\n", gp->name));
+			goto err;
+		}
+	if (sc->offsets[sc->nblocks] > pp->mediasize)
+		if (sc->offsets[i] - sc->offsets[i - 1] <= 0) {
+			DPRINTF(("%s: incorrect offsets table\n", gp->name));
+			goto err;
+		}
+
 	DPRINTF(("%s: done reading offsets\n", gp->name));
 	mtx_init(&sc->last_mtx, "geom_uzip cache", NULL, MTX_DEF);
 	sc->last_blk = -1;
@@ -481,41 +553,130 @@
 	return (NULL);
 }
 
-static int
-g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
+static __inline__ const char *
+g_uzip_skip_dir(const char *name)
+{
+	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
+		name += strlen("/dev/");
+
+	return (name);
+}
+
+static struct g_geom *
+g_uzip_find_geom(struct g_class *mp, const char *name)
 {
+	struct g_geom *gp;
 	struct g_provider *pp;
+	const char *pname;
+
+	if (name == NULL)
+		return NULL;
 
-	g_trace(G_T_TOPOLOGY, "g_uzip_destroy_geom(%s, %s)", mp->name, gp->name);
+	name = g_uzip_skip_dir(name);
+	LIST_FOREACH(gp, &mp->geom, geom) {
+		pp = LIST_FIRST(&gp->provider);
+		if (pp == NULL)
+			return NULL;
+		pname = g_uzip_skip_dir(pp->name);
+		if (strcmp(pname, name) == 0)
+			return (gp);
+	}
+	return (NULL);
+}
+
+static void
+g_uzip_ctl(struct gctl_req *req, struct g_class *mp, const char *cmd)
+{
+	struct g_geom *gp;
+	struct g_provider *pp;
+	int *nargs, *force;
+	register int i;
+	int error;
+	char param[16];
+	const char *name;
+	
+	DPRINTF(("%s: g_uzip_ctl, cmd = %s\n", mp->name, cmd));
 	g_topology_assert();
 
-	if (gp->softc == NULL) {
-		printf("%s(%s): gp->softc == NULL\n", __func__, gp->name);
-		return (ENXIO);
+	if (strcmp(cmd, "destroy") == 0) {
+		nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
+        	if (nargs == NULL)
+			return;
+
+		if (*nargs <= 0) {
+			gctl_error(req, "Missing device(s).");
+			return;
+		}
+		force = gctl_get_paraml(req, "force", sizeof(*force));
+		if (force == NULL)
+			return;
+
+		for (i = 0; i < *nargs; i++) {
+ 			snprintf(param, sizeof(param), "arg%d", i);
+			name = gctl_get_asciiparam(req, param);
+			if (name == NULL)
+				return;
+			gp = g_uzip_find_geom(mp, name);
+			if (gp == NULL) {
+				gctl_error(req, "Invalid provider: %s .", name);
+				return;
+			}
+
+			error = g_uzip_destroy(gp, *force);
+			if (error != 0) {
+				gctl_error(req, "Cannot destroy %s (error=%d).",
+				    name, error);
+				return;
+			}
+		}
 	}
+	else if (strcmp(cmd, "taste") == 0) {
+		nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
+        	if (nargs == NULL)
+			return;
 
-	KASSERT(gp != NULL, ("NULL geom"));
-	pp = LIST_FIRST(&gp->provider);
-	KASSERT(pp != NULL, ("NULL provider"));
-	if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)
-		return (EBUSY);
+		if (*nargs <= 0) {
+			gctl_error(req, "Missing device(s).");
+			return;
+		}
 
-	g_uzip_softc_free(gp->softc, gp);
-	gp->softc = NULL;
-	g_wither_geom(gp, ENXIO);
-	return (0);
+		for (i = 0; i < *nargs; i++) {
+ 			snprintf(param, sizeof(param), "arg%d", i);
+			name = gctl_get_asciiparam(req, param);
+			if (name == NULL)
+				return;
+			name = g_uzip_skip_dir(name);
+			pp = g_provider_by_name(name);
+			if (pp == NULL) {
+				gctl_error(req, "Invalid provider: %s .", name);
+				return;
+			}
+
+			(void)g_uzip_taste(mp, pp, 0);
+		}
+	}
+	else
+		gctl_error(req, "Unknown cmd.");
+}
+
+static int
+g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
+{
+	DPRINTF(("%s: g_uzip_destroy_geom\n", gp->name));
+
+	return (g_uzip_destroy(gp, 0));
 }
 
 static struct g_class g_uzip_class = {
 	.name = UZIP_CLASS_NAME,
 	.version = G_VERSION,
 	.taste = g_uzip_taste,
-	.destroy_geom = g_uzip_destroy_geom,
-
 	.start = g_uzip_start,
 	.orphan = g_uzip_orphan,
 	.access = g_uzip_access,
 	.spoiled = g_uzip_spoiled,
+	.ctlreq = g_uzip_ctl,
+	.destroy_geom = g_uzip_destroy_geom,
 };
 
 DECLARE_GEOM_CLASS(g_uzip_class, geom_uzip);
--- 1.diff ends here ---

--- 2.diff begins here ---
--- sbin/geom/class/Makefile.orig	Wed Jul 27 18:36:37 2005
+++ sbin/geom/class/Makefile	Wed Jul 27 18:36:48 2005
@@ -7,5 +7,6 @@
 SUBDIR+=raid3
 SUBDIR+=shsec
 SUBDIR+=stripe
+SUBDIR+=uzip
 
 .include <bsd.subdir.mk>
--- 2.diff ends here ---

--- 1.shar begins here ---
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	sbin/geom/class/uzip
#	sbin/geom/class/uzip/Makefile
#	sbin/geom/class/uzip/guzip.8
#	sbin/geom/class/uzip/geom_uzip.h
#	sbin/geom/class/uzip/geom_uzip.c
#
echo c - sbin/geom/class/uzip
mkdir -p sbin/geom/class/uzip > /dev/null 2>&1
echo x - sbin/geom/class/uzip/Makefile
sed 's/^X//' >sbin/geom/class/uzip/Makefile << 'END-of-sbin/geom/class/uzip/Makefile'
X# $FreeBSD: src/sbin/geom/class/label/Makefile,v 1.1 2004/07/02 19:40:34 pjd Exp $
X
X.PATH: ${.CURDIR}/../../misc
X
XLDFLAGS+= -lm -lz
XCLASS=	uzip
X
X.include <bsd.lib.mk>
END-of-sbin/geom/class/uzip/Makefile
echo x - sbin/geom/class/uzip/guzip.8
sed 's/^X//' >sbin/geom/class/uzip/guzip.8 << 'END-of-sbin/geom/class/uzip/guzip.8'
X.\"
X.\" Copyright (c) 2005 Stanislav Sedov
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer,
X.\"    without modification, immediately at the beginning of the file.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
X.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X.\"
X.\"
X.Dd Jul 25, 2005
X.Os
X.Dt GUZIP 8
X.Sh NAME
X.Nm guzip
X.Nd "control utility for UZIP GEOM class"
X.Sh SYNOPSIS
X.Nm
X.Cm destroy
X.Op Fl fv
X.Ar name
X.Nm
X.Cm taste
X.Op Fl v
X.Ar name
X.Nm
X.Cm create
X.Op Fl v
X.Op Fl B|L
X.Op Fl b Ar blocksize
X.Op Fl l Ar compression
X.Op Fl o Ar file
X.Ar file
X.Nm
X.Cm restore
X.Op Fl v
X.Op Fl o Ar file
X.Ar file
X.Nm
X.Cm getinfo
X.Ar file
X.Nm
X.Cm help
X.Nm
X.Cm list
X.Op Ar name Ar
X.Nm
X.Cm status
X.Op Fl s
X.Op Ar name Ar
X.Nm
X.Cm load
X.Op Fl v
X.Nm
X.Cm unload
X.Op Fl v
X.Sh DESCRIPTION
XThe
X.Nm
Xutility is used to create and extract UZIP images and control GEOM UZIP class.
X.Pp
XThe first argumen to
X.Nm
Xindicates an action to be performed. It may be one of:
X.Pp
X.Bl -tag -width XXXXXXXXXXXX
X.It Cm destroy
Xdestroy GEOM UZIP provider
X.It Cm taste
Xtaste specified device for UZIP magic
X.It Cm create
Xcreate compressed image
X.It Cm extract
Xuncompress existing image
X.It Cm getinfo
Xget info about image
X.It Cm help
Xdisplay help message and exit
X.It Cm list
XSee
X.Xr geom 8 .
X.It Cm status
XSee
X.Xr geom 8 .
X.It Cm load
XSee
X.Xr geom 8 .
X.It Cm unload
XSee
X.Xr geom 8 .
X.El
X.Pp
XAvailable options:
X.Pp
X.Bl -tag -width XXXXXXXXXXXX
X.It Fl B
Xcreate image in big-endian format
X.It Fl L
Xcreate image in little-endian format
X.It Fl b Ar blocksize
Xuse specified blocksize (must be multiple of 512). Default value is 65536.
X.It Fl l
Xcompression level (1-9). 9 is the best.
X.It Fl o
Xsend output to specified file.
X.It Fl f
Xforce operation to be performed.
X.It Fl v
Xbe more verbose.
X.El
X.Pp
X.Sh EXAMPLES
XThe typical usage for creating uzip image:
X.Pp
X.Dl "guzip create -o compressed_image image"
X.Pp
XThe typical usage for extracting compressed image:
X.Pp
X.Dl "guzip extract -o image compressed_image"
X.Pp
XYou can get info about image using:
X.Pp
X.Dl "guzip getinfo compressed_image"
X.Pp
XIf you want to destroy UZIP provider. md0.uzip for example, use:
X.Pp
X.Dl "guzip destroy /dev/md0.uzip"
X.Pp
XUse following command to create provider again:
X.Pp
X.Dl "guzip taste /dev/md0"
X.Pp
X.Sh SEE ALSO
X.Xr geom 4 ,
X.Xr geom 8
X.Sh AUTHORS
XThe
X.Nm
Xutility and this manpage was contributed by
X.An Stanislav Sedov. The GEOM UZIP class implementation was written by Max Khon.
X.Sh BUGS
XProbably, please report when found.
END-of-sbin/geom/class/uzip/guzip.8
echo x - sbin/geom/class/uzip/geom_uzip.h
sed 's/^X//' >sbin/geom/class/uzip/geom_uzip.h << 'END-of-sbin/geom/class/uzip/geom_uzip.h'
X#ifndef _GEOM_UZIP_H_
X#define _GEOM_UZIP_H
X
X#define GUZIP_MAGIC_LEN 20
X#define GUZIP_MAGIC "<FreeBSD-GEOM-UZIP>"
X#define DEFAULT_BLOCKSIZE 65536
X#define DEF_MODE 0644
X
Xstruct guzip_header {
X	char		magic[GUZIP_MAGIC_LEN];
X	uint		lorder;
X	int64_t		fsize;
X	int32_t		blocksize;
X	int32_t		nblocks;
X};
X
Xtypedef struct guzip_header guzip_header_t;
X
X#endif /* GEOM_UZIP_H */
END-of-sbin/geom/class/uzip/geom_uzip.h
echo x - sbin/geom/class/uzip/geom_uzip.c
sed 's/^X//' >sbin/geom/class/uzip/geom_uzip.c << 'END-of-sbin/geom/class/uzip/geom_uzip.c'
X/*-
X * Copyright (c) 2005 Stanislav Sedov
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 
X * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#include <stdlib.h>
X#include <unistd.h>
X#include <stdio.h>
X#include <string.h>
X#include <strings.h>
X#include <fcntl.h>
X#include <err.h>
X#include <sysexits.h>
X#include <zlib.h>
X#include <math.h>
X#include <assert.h>
X#include <libgeom.h>
X#include <stdint.h>
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/endian.h>
X#include <sys/stat.h>
X
X#include <netinet/in.h>
X
X#include "core/geom.h"
X#include "misc/subr.h"
X#include "geom_uzip.h"
X
X/* Protos */
Xstatic void		guzip_compress		__P((int in, int out));
Xstatic void		guzip_uncompress	__P((int in, int out));
Xstatic void		guzip_getinfo		__P((int in));
Xstatic const char *	zlib_strerror		__P((int code));
Xstatic void		geom_uzip_main		__P((struct gctl_req *req, \
X						    unsigned flags));
X/* Global data */
Xuint32_t lib_version = G_LIB_VERSION;
Xuint32_t version = 1;
Xstatic int compression = Z_DEFAULT_COMPRESSION;
Xstatic uint32_t default_blocksize = DEFAULT_BLOCKSIZE; 
Xstatic const char *infname;
Xstatic char default_outfname[] = "/dev/stdout";
Xstatic const char *outfname;
Xstatic int verbose = 0;
Xstatic guzip_header_t header;
X
Xstruct g_command class_commands[] = {
X	{ "destroy", G_FLAG_VERBOSE, NULL,
X	    {
X		{ 'f', "force", NULL, G_TYPE_NONE },
X		G_OPT_SENTINEL
X	    },
X	    "[-fv] name ..."
X	},
X	{ "taste", G_FLAG_VERBOSE, NULL,
X	    {
X		G_OPT_SENTINEL
X	    },
X	    "[-v] name ..."
X	},
X	{ "create", G_FLAG_VERBOSE, geom_uzip_main,
X	    {
X		{ 'B', "big-endian", NULL, G_TYPE_NONE },
X		{ 'L', "lit-endian", NULL, G_TYPE_NONE },
X		{ 'b', "blocksize", &default_blocksize, G_TYPE_NUMBER },
X		{ 'l', "compression level", &compression, G_TYPE_NUMBER },
X		{ 'o', "outfilename", default_outfname, G_TYPE_STRING },
X		G_OPT_SENTINEL
X	    },
X	    "[-v] [-B|L] [-b blocksize] [-l level] [-o file] file"
X	},
X	{ "restore", G_FLAG_VERBOSE, geom_uzip_main,
X	    {
X		{ 'o', "outfilename", default_outfname, G_TYPE_STRING },
X		G_OPT_SENTINEL
X	    },
X	    "[-v] [-o file] file"
X	},
X	{ "getinfo", 0, geom_uzip_main, G_NULL_OPTS,
X	    "file"
X	},
X	G_CMD_SENTINEL
X};
X
Xstatic void
Xgeom_uzip_main(req, flags)
X	struct gctl_req *req;
X	unsigned flags;
X{
X	int in, out = 0;
X	intmax_t *valp;
X	const char *str;
X	const char *cmd;
X	int *nargs, *bendian, *lendian;
X
X	header.lorder = htonl(BYTE_ORDER);
X	bcopy(GUZIP_MAGIC, header.magic, GUZIP_MAGIC_LEN);
X
X	if ((flags & G_FLAG_VERBOSE) != 0)
X		verbose = 1;
X
X        nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
X        if (nargs == NULL) {
X                gctl_error(req, "No '%s' argument.", "nargs");
X		return;
X        }
X        if (*nargs < 1)
X                errx(EX_USAGE, "You must specify file");
X		
X	infname = gctl_get_asciiparam(req, "arg0");
X
X	if ((in = open(infname, O_RDONLY, 0)) < 0)
X		err(EX_IOERR, "open(%s)", infname);
X
X	cmd = gctl_get_asciiparam(req, "verb");
X	if (cmd == NULL) {
X		gctl_error(req, "No '%s' argument.", "verb");
X		return;
X	}
X	if (strcmp(cmd, "create") == 0) {
X		valp = gctl_get_paraml(req, "blocksize", \
X				       sizeof(*valp));
X		if (valp == NULL) {
X			gctl_error(req, "No '%s' argument.", "blocksize");
X			return;
X		}
X		header.blocksize = (uint32_t)*valp;
X		if (header.blocksize <= 0)	
X			errx(EX_USAGE, "Invalid blocksize: %d", \
X			    header.blocksize);
X		if ((header.blocksize % 512) != 0)
X			errx(EX_USAGE, "Blocksize must be a multiple of 512");
X
X		valp = gctl_get_paraml(req, "compression level", \
X				       sizeof(*valp));
X		if (valp == NULL) {
X			gctl_error(req, "No '%s' argument.", "compression");
X			return;
X		}
X		compression = (int)*valp;
X		if (compression < -1 || compression > 9)
X			errx(EX_USAGE, "Invalid compression ratio: %d", \
X			    compression);
X
X		str = gctl_get_asciiparam(req, "outfilename");
X		if (str == NULL) {
X			gctl_error(req, "No '%s' argument.", "file");
X			return;
X		}
X		outfname = str;
X
X		bendian = gctl_get_paraml(req, "big-endian", sizeof(*bendian));
X		if (bendian == NULL) {
X			gctl_error(req, "No '%s' argument.", "big-endian");
X			return;
X		}
X		lendian = gctl_get_paraml(req, "lit-endian", sizeof(*lendian));
X		if (lendian == NULL) {
X			gctl_error(req, "No '%s' argument.", "little-endian");
X			return;
X		}
X
X		if (*bendian != 0 && *lendian != 0)
X			errx(EX_USAGE, "You must specify either big-endian or" \
X			    " little-endian.");
X		else if (*bendian != 0)
X			header.lorder = htonl(BIG_ENDIAN);
X		else if (*lendian != 0)
X			header.lorder = htonl(LITTLE_ENDIAN);
X
X		if ((out = open(outfname, O_CREAT | O_WRONLY | O_EXLOCK | \
X			       O_TRUNC, DEF_MODE)) < 0)
X			err(EX_IOERR, "open(%s)", outfname);
X
X		guzip_compress(in, out);
X	}
X	else if (strcmp(cmd, "restore") == 0) {
X		str = gctl_get_asciiparam(req, "outfilename");
X		if (str == NULL) {
X			gctl_error(req, "No '%s' argument.", "file");
X			return;
X		}
X		outfname = str;
X
X		if ((out = open(outfname, O_CREAT | O_WRONLY | O_EXLOCK | \
X			       O_TRUNC, DEF_MODE)) < 0)
X			err(EX_IOERR, "open(%s)", outfname);
X
X		guzip_uncompress(in, out);
X	}
X	else if (strcmp(cmd, "getinfo") == 0)
X		guzip_getinfo(in);
X	else {
X		gctl_error(req, "Unknown command: %s.", cmd);
X		exit(EX_USAGE);
X	}
X
X	close(in);
X	close(out);
X
X}
X
Xstatic const char *
Xzlib_strerror(code)
X	int code;
X{
X	const char *values[] = {
X		"Z_OK",
X		"Z_STREAM_END",
X		"Z_NEED_DICT",
X		"Z_ERRNO",
X		"Z_STREAM_ERROR",
X		"Z_DATA_ERROR",
X		"Z_MEM_ERROR",
X		"Z_BUF_ERROR",
X		"Z_VERSION_ERROR",
X		"Z_UNKNOWN_ERROR"
X	};
X
X	switch (code) {
X	case Z_OK:
X		return(values[0]);
X		break;
X	case Z_STREAM_END:
X		return(values[1]);
X		break;
X	case Z_NEED_DICT:
X		return(values[2]);
X		break;
X	case Z_ERRNO:
X		return(values[3]);
X		break;
X	case Z_STREAM_ERROR:
X		return(values[4]);
X		break;
X	case Z_DATA_ERROR:
X		return(values[5]);
X		break;
X	case Z_MEM_ERROR:
X		return(values[6]);
X		break;
X	case Z_BUF_ERROR:
X		return(values[7]);
X		break;
X	case Z_VERSION_ERROR:
X		return(values[8]);
X		break;
X	default:
X		return(values[9]);
X		break;
X	};
X}
X
Xstatic void
Xguzip_compress(in, out)
X	int in;
X	int out;
X{
X	struct stat sb;
X	uint8_t *inbuf, *outbuf;
X	uint64_t *atable; /* Allocation table */
X	unsigned long len;
X	size_t compsize, atablesize;
X	int ret;
X	register int i;
X
X	if (fstat(in, &sb) != 0)
X		err(EX_IOERR, "fstat(%s)", infname);
X
X	header.fsize = sb.st_size;
X	header.nblocks = ceilf((float)header.fsize / header.blocksize);
X
X	if (verbose)
X		fprintf(stderr, "Original file size: %lld\nCompressing "\
X		    "%d %d-byte blocks...\n", header.fsize,		\
X		    header.nblocks, header.blocksize);
X
X	/* Evaluate max compressed block's size */
X	compsize = compressBound(header.blocksize);
X
X	atablesize = header.nblocks * sizeof(uint64_t);
X
X	if (ftruncate(out, sizeof(header) + atablesize) != 0)
X		err(EX_IOERR, "ftruncate(%s)", outfname);
X	if ((lseek(out, sizeof(header) + atablesize,\
X		SEEK_SET)) != sizeof(header) + atablesize)
X		err(EX_IOERR, "lseek(%s)", outfname);
X	
X	/* Allocate memory for input buffer */
X	if ((inbuf = malloc(header.blocksize)) == NULL)
X		err(EX_OSERR, "malloc(%d)", header.blocksize); 
X
X	/* Allocate memory for allocation table */
X	if ((atable = malloc(atablesize + sizeof(uint64_t))) == NULL)
X		err(EX_OSERR, "malloc(%d)", atablesize + sizeof(uint64_t));
X
X	/* Allocate memory for compressed blocks */
X	if ((outbuf = malloc(compsize)) == NULL)
X		err(EX_OSERR, "malloc(%d)", compsize); 
X
X	atable[0] = sizeof(header) + atablesize;
X
X	for(i = 1; i <= header.nblocks; i++) {
X		ret = read(in, inbuf, header.blocksize);
X		if (ret == -1)
X			err(EX_IOERR, "read(%s)", infname);
X		else if (ret != header.blocksize && i != header.nblocks)
X			errx(EX_IOERR, "can't read block: file too small");
X
X		len = compsize;
X		ret = compress2(outbuf, &len, inbuf,
X				ret, compression);
X		if (ret != Z_OK)
X			errx(EX_SOFTWARE, "compress(): %s", zlib_strerror(ret));
X		atable[i] = atable[i - 1] + len;
X
X		ret = write(out, outbuf, len);
X		if (ret == -1)
X			err(EX_IOERR, "write(%s)", outfname);
X		else if ((uint32_t)ret != len)
X			errx(EX_IOERR, "can't write block");
X
X		if (verbose)
X			fprintf(stderr, "progress: %5.2f%%\r",\
X			    100.0 * i / header.nblocks);
X	}
X	
X	fprintf(stderr, "\n");
X
X	/* Translate allocation table, if need */
X	if (header.lorder != htonl(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN)
X		for (i = 1; i <= header.nblocks; i++)
X			atable[i] = htobe64(atable[i]);
X	else if (header.lorder != htonl(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN)
X		for (i = 1; i <= header.nblocks; i++)
X			atable[i] = htole64(atable[i]);
X
X	/* Header always in big endian */
X	header.fsize = htobe64(header.fsize);
X	header.nblocks = htobe32(header.nblocks);
X	header.blocksize = htobe32(header.blocksize);
X
X	/* Seek to begin of file */
X	if ((lseek(out, 0, SEEK_SET)) != 0)
X		err(EX_IOERR, "seek(%s)", outfname);
X
X	ret = write(out, &header, sizeof(header));
X	if (ret == -1)
X		err(EX_IOERR, "write(%s)", outfname);
X	else if ((uint32_t)ret != sizeof(header))
X		errx(EX_IOERR, "can't save header");
X
X	ret = write(out, &atable[1], atablesize);
X	if (ret == -1)
X		err(EX_IOERR, "write(%s)", outfname);
X	else if ((uint32_t)ret != atablesize)
X		errx(EX_IOERR, "can't save allocation table");
X
X	free(inbuf);
X	free(outbuf);
X	free(atable);
X}
X
Xstatic void
Xguzip_uncompress(in, out)
X	int in;
X	int out;
X{
X	uint8_t *inbuf, *outbuf;
X	uint64_t *atable;
X	unsigned long len;
X	size_t compsize, atablesize;
X	int ret;
X	register int i;
X
X	ret = read(in, &header, sizeof(header));
X	if (ret == -1)
X		err(EX_IOERR, "read(%s)", infname);
X	else if ((uint32_t)ret < sizeof(header))
X		errx(EX_IOERR, "can't read file header: %s", infname);
X
X	if (bcmp(header.magic, GUZIP_MAGIC, GUZIP_MAGIC_LEN) != 0)
X		errx(EX_DATAERR, "invalid magick: %s", infname);
X
X	/* Header always in big endian */
X	header.fsize = be64toh(header.fsize);
X	header.nblocks = be32toh(header.nblocks);
X	header.blocksize = be32toh(header.blocksize);
X
X	if (header.nblocks < 0 || header.blocksize < 0 || header.fsize < 0)
X		errx(EX_DATAERR, "header corrupted");
X
X	atablesize = header.nblocks * sizeof(uint64_t);
X
X	compsize = compressBound(header.blocksize);
X
X	/* Allocate memory for input buffer */
X	if ((inbuf = malloc(compsize)) == NULL)
X		err(EX_OSERR, "malloc(%d)", header.blocksize); 
X
X	/* Allocate memory for atable list */
X	if ((atable = malloc(atablesize + sizeof(uint64_t))) == NULL)
X		err(EX_OSERR, "malloc(%d)", atablesize);
X
X	/* Allocate memory for compressed blocks */
X	if ((outbuf = malloc(header.blocksize)) == NULL)
X		err(EX_OSERR, "malloc(%d)", compsize); 
X
X	ret = read(in, &atable[1], atablesize);
X	if (ret == -1)
X		err(EX_IOERR, "read(%s)", infname);
X	else if ((uint32_t)ret != atablesize)
X		errx(EX_IOERR, "can't read allocation table: %s", infname);
X
X	atable[0] = sizeof(header) + atablesize;
X
X	if (header.lorder != htonl(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN)
X		for (i = 1; i <= header.nblocks; i++)
X			atable[i] = be64toh(atable[i]);
X	else if (header.lorder != htonl(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN)
X		for (i = 1; i <= header.nblocks; i++)
X			atable[i] = le64toh(atable[i]);
X
X	if (verbose)
X		fprintf(stderr, "Original file size: %lld\n"	\
X		    "Decompressing "				\
X		    "%d %d-byte blocks...\n", header.fsize,	\
X		    header.nblocks, header.blocksize);
X
X	for(i = 0; i < header.nblocks; i++) {
X		len = atable[i+1] - atable[i];
X		ret = read(in, inbuf, len);
X		if (ret == -1)
X			err(EX_IOERR, "read(%s)", infname);
X		else if ((uint32_t)ret != len)
X			errx(EX_IOERR, "can't read block: %s", infname);
X
X		len = header.blocksize;
X		ret = uncompress(outbuf, &len, inbuf,
X			(unsigned long)(atable[i+1] - atable[i]));
X		if (ret != Z_OK)
X			errx(EX_SOFTWARE, "uncompress(): %s",\
X			    zlib_strerror(ret));
X
X		ret = write(out, outbuf, len);
X		if (ret == -1)
X			err(EX_IOERR, "write(%s)", outfname);
X		else if ((uint32_t)ret < len)
X			errx(EX_IOERR, "can't write block: %s", outfname);
X
X		if (verbose)
X			fprintf(stderr, "progress: %5.2f%%\r",\
X			    100.0 * (i + 1) / header.nblocks);
X	}
X
X	fprintf(stderr, "\n");
X
X	free(inbuf);
X	free(outbuf);
X	free(atable);
X}
X
Xstatic void
Xguzip_getinfo(in)
X	int in;
X{
X	int ret;
X
X	ret = read(in, &header, sizeof(header));
X	if (ret == -1)
X		err(EX_IOERR, "read(%s)", infname);
X	else if ((uint32_t)ret < sizeof(header))
X		errx(EX_IOERR, "can't read file header: %s", infname);
X
X	if (bcmp(header.magic, GUZIP_MAGIC, GUZIP_MAGIC_LEN) != 0)
X		errx(EX_DATAERR, "invalid magick: %s", infname);
X
X	/* Header always in big endian */
X	header.fsize = be64toh(header.fsize);
X	header.nblocks = be32toh(header.nblocks);
X	header.blocksize = be32toh(header.blocksize);
X
X	if (header.nblocks < 0 || header.blocksize < 0 || header.fsize < 0)
X		errx(EX_DATAERR, "header corrupted");
X
X	printf("Image size: %lld\nBlock size: %d\nNumber of blocks: %d\n"\
X	    "Endianess: %s\n",						\
X	    header.fsize, header.blocksize, header.nblocks,		\
X	    be32toh(header.lorder) == BIG_ENDIAN ? "BIG ENDIAN" :	\
X	    "LITTLE ENDIAN");
X}
END-of-sbin/geom/class/uzip/geom_uzip.c
exit
--- 1.shar ends here ---

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list