diff options
Diffstat (limited to 'usr/src/cmd/boot/fiocompress/fiocompress.c')
| -rw-r--r-- | usr/src/cmd/boot/fiocompress/fiocompress.c | 316 |
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); + } +} |
