summaryrefslogtreecommitdiff
path: root/usr/src/cmd/boot/fiocompress/fiocompress.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/boot/fiocompress/fiocompress.c')
-rw-r--r--usr/src/cmd/boot/fiocompress/fiocompress.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/usr/src/cmd/boot/fiocompress/fiocompress.c b/usr/src/cmd/boot/fiocompress/fiocompress.c
new file mode 100644
index 0000000000..cef348b158
--- /dev/null
+++ b/usr/src/cmd/boot/fiocompress/fiocompress.c
@@ -0,0 +1,316 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * fiocompress - a utility to compress files with a filesystem.
+ * Used to build compressed boot archives to reduce memory
+ * requirements for booting.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <utility.h>
+#include <zlib.h>
+
+#include <sys/filio.h>
+#include <sys/fs/decomp.h>
+
+#include "message.h"
+
+static void setup_infile(char *);
+static void setup_outfile(char *);
+static void do_comp(size_t);
+static void do_decomp(void);
+
+static caddr_t srcaddr;
+static size_t srclen;
+
+static int dstfd;
+
+static char *srcfile;
+static char *dstfile;
+
+
+int
+main(int argc, char **argv)
+{
+ int compress = 0;
+ int decompress = 0;
+ int doioc = 0;
+ size_t blksize = 8192;
+ char c;
+
+ while ((c = getopt(argc, argv, "mcdb:")) != -1) {
+ switch (c) {
+ case 'm':
+ doioc++;
+ break;
+ case 'c':
+ if (decompress) {
+ (void) fprintf(stderr, OPT_DC_EXCL);
+ exit(-1);
+ }
+ compress = 1;
+ break;
+ case 'd':
+ if (compress) {
+ (void) fprintf(stderr, OPT_DC_EXCL);
+ exit(-1);
+ }
+ decompress = 1;
+ break;
+ case 'b':
+ blksize = atoi(optarg);
+ if (blksize == 0 || (blksize & (blksize-1))) {
+ (void) fprintf(stderr, INVALID_BLKSZ);
+ exit(-1);
+ }
+ break;
+ case '?':
+ (void) fprintf(stderr, UNKNOWN_OPTION, optopt);
+ exit(-1);
+ }
+ }
+ if (argc - optind != 2) {
+ (void) fprintf(stderr, MISS_FILES);
+ exit(-1);
+ }
+
+ setup_infile(argv[optind]);
+ setup_outfile(argv[optind + 1]);
+
+ if (decompress)
+ do_decomp();
+ else {
+ do_comp(blksize);
+ if (doioc) {
+ if (ioctl(dstfd, _FIO_COMPRESSED, 0) == -1) {
+ (void) fprintf(stderr, FIO_COMP_FAIL,
+ dstfile, strerror(errno));
+ exit(-1);
+ }
+ }
+ }
+ return (0);
+}
+
+static void
+setup_infile(char *file)
+{
+ int fd;
+ void *addr;
+ struct stat stbuf;
+
+ srcfile = file;
+
+ fd = open(srcfile, O_RDONLY, 0);
+ if (fd == -1) {
+ (void) fprintf(stderr, CANT_OPEN,
+ srcfile, strerror(errno));
+ exit(-1);
+ }
+
+ if (fstat(fd, &stbuf) == -1) {
+ (void) fprintf(stderr, STAT_FAIL,
+ srcfile, strerror(errno));
+ exit(-1);
+ }
+ srclen = stbuf.st_size;
+
+ addr = mmap(0, srclen, PROT_READ, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ (void) fprintf(stderr, MMAP_FAIL, srcfile, strerror(errno));
+ exit(-1);
+ }
+ srcaddr = addr;
+}
+
+static void
+setup_outfile(char *file)
+{
+ int fd;
+
+ dstfile = file;
+
+ fd = open(dstfile, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd == -1) {
+ (void) fprintf(stderr, OPEN_FAIL, dstfile, strerror(errno));
+ exit(-1);
+ }
+ dstfd = fd;
+}
+
+static void
+do_comp(size_t blksize)
+{
+ struct comphdr *hdr;
+ off_t offset;
+ size_t blks, dstlen, hlen;
+ void *dstbuf;
+ int i;
+
+ blks = ((srclen - 1) / blksize) + 1;
+ hlen = offset = sizeof (struct comphdr) + blks * sizeof (uint64_t);
+ hdr = malloc(hlen);
+ if (hdr == NULL) {
+ (void) fprintf(stderr, HDR_ALLOC, hlen);
+ exit(-1);
+ }
+
+ hdr->ch_magic = CH_MAGIC;
+ hdr->ch_version = CH_VERSION;
+ hdr->ch_algorithm = CH_ALG_ZLIB;
+ hdr->ch_fsize = srclen;
+ hdr->ch_blksize = blksize;
+
+ dstlen = ZMAXBUF(blksize);
+ dstbuf = malloc(dstlen);
+ if (dstbuf == NULL) {
+ (void) fprintf(stderr, BUF_ALLOC, dstlen);
+ exit(-1);
+ }
+
+ if (lseek(dstfd, offset, SEEK_SET) == (off_t)-1) {
+ (void) fprintf(stderr, SEEK_ERR,
+ offset, dstfile, strerror(errno));
+ exit(-1);
+ }
+
+ for (i = 0; i < blks; i++) {
+ ulong_t slen, dlen;
+ int ret;
+
+ hdr->ch_blkmap[i] = offset;
+ slen = MIN(srclen, blksize);
+ dlen = dstlen;
+ ret = compress2(dstbuf, &dlen, (Bytef *)srcaddr, slen, 9);
+ if (ret != Z_OK) {
+ (void) fprintf(stderr, COMP_ERR, srcfile, ret);
+ exit(-1);
+ }
+
+ if (write(dstfd, dstbuf, dlen) != dlen) {
+ (void) fprintf(stderr, WRITE_ERR,
+ dlen, dstfile, strerror(errno));
+ exit(-1);
+ }
+
+ offset += dlen;
+ srclen -= slen;
+ srcaddr += slen;
+ }
+
+ if (lseek(dstfd, 0, SEEK_SET) == (off_t)-1) {
+ (void) fprintf(stderr, SEEK_ERR,
+ 0, dstfile, strerror(errno));
+ exit(-1);
+ }
+
+ if (write(dstfd, hdr, hlen) != hlen) {
+ (void) fprintf(stderr, WRITE_ERR,
+ hlen, dstfile, strerror(errno));
+ exit(-1);
+ }
+}
+
+static void
+do_decomp()
+{
+ struct comphdr *hdr;
+ size_t blks, blksize;
+ void *dstbuf;
+ int i;
+ ulong_t slen, dlen;
+ int ret;
+
+ hdr = (struct comphdr *)(void *)srcaddr;
+ if (hdr->ch_magic != CH_MAGIC) {
+ (void) fprintf(stderr, BAD_MAGIC,
+ srcfile, (uint64_t)hdr->ch_magic, CH_MAGIC);
+ exit(-1);
+ }
+ if (hdr->ch_version != CH_VERSION) {
+ (void) fprintf(stderr, BAD_VERS,
+ srcfile, (uint64_t)hdr->ch_version, CH_VERSION);
+ exit(-1);
+ }
+ if (hdr->ch_algorithm != CH_ALG_ZLIB) {
+ (void) fprintf(stderr, BAD_ALG,
+ srcfile, (uint64_t)hdr->ch_algorithm, CH_ALG_ZLIB);
+ exit(-1);
+ }
+
+ blksize = hdr->ch_blksize;
+ dstbuf = malloc(blksize);
+ if (dstbuf == NULL) {
+ (void) fprintf(stderr, HDR_ALLOC, blksize);
+ exit(-1);
+ }
+
+ blks = (hdr->ch_fsize - 1) / blksize;
+ srcaddr += hdr->ch_blkmap[0];
+ for (i = 0; i < blks; i++) {
+ dlen = blksize;
+ slen = hdr->ch_blkmap[i + 1] - hdr->ch_blkmap[i];
+ ret = uncompress(dstbuf, &dlen, (Bytef *)srcaddr, slen);
+ if (ret != Z_OK) {
+ (void) fprintf(stderr, DECOMP_ERR, srcfile, ret);
+ exit(-1);
+ }
+
+ if (dlen != blksize) {
+ (void) fprintf(stderr, CORRUPT, srcfile);
+ exit(-1);
+ }
+ if (write(dstfd, dstbuf, dlen) != dlen) {
+ (void) fprintf(stderr, WRITE_ERR,
+ dlen, dstfile, strerror(errno));
+ exit(-1);
+ }
+ srcaddr += slen;
+ }
+
+ dlen = blksize;
+ slen = hdr->ch_fsize - hdr->ch_blkmap[i];
+ if ((ret = uncompress(dstbuf, &dlen, (Bytef *)srcaddr, slen)) != Z_OK) {
+ (void) fprintf(stderr, DECOMP_ERR, dstfile, ret);
+ exit(-1);
+ }
+
+ if (write(dstfd, dstbuf, dlen) != dlen) {
+ (void) fprintf(stderr, WRITE_ERR,
+ dlen, dstfile, strerror(errno));
+ exit(-1);
+ }
+}