Home | History | Annotate | Download | only in fiocompress
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * fiocompress - a utility to compress files with a filesystem.
     28  * Used to build compressed boot archives to reduce memory
     29  * requirements for booting.
     30  */
     31 
     32 #include <stdio.h>
     33 #include <errno.h>
     34 #include <stdlib.h>
     35 #include <fcntl.h>
     36 #include <sys/types.h>
     37 #include <sys/stat.h>
     38 #include <sys/mman.h>
     39 #include <unistd.h>
     40 #include <utility.h>
     41 #include <zlib.h>
     42 
     43 #include <sys/filio.h>
     44 #include <sys/fs/decomp.h>
     45 
     46 #include "message.h"
     47 
     48 static void	setup_infile(char *);
     49 static void	setup_outfile(char *);
     50 static void	do_comp(size_t);
     51 static void	do_decomp(void);
     52 
     53 static caddr_t	srcaddr;
     54 static size_t	srclen;
     55 
     56 static int	dstfd;
     57 
     58 static char	*srcfile;
     59 static char	*dstfile;
     60 
     61 
     62 int
     63 main(int argc, char **argv)
     64 {
     65 	int compress = 0;
     66 	int decompress = 0;
     67 	int doioc = 0;
     68 	size_t	blksize = 8192;
     69 	char c;
     70 
     71 	while ((c = getopt(argc, argv, "mcdb:")) != -1) {
     72 		switch (c) {
     73 		case 'm':
     74 			doioc++;
     75 			break;
     76 		case 'c':
     77 			if (decompress) {
     78 				(void) fprintf(stderr, OPT_DC_EXCL);
     79 				exit(-1);
     80 			}
     81 			compress = 1;
     82 			break;
     83 		case 'd':
     84 			if (compress) {
     85 				(void) fprintf(stderr, OPT_DC_EXCL);
     86 				exit(-1);
     87 			}
     88 			decompress = 1;
     89 			break;
     90 		case 'b':
     91 			blksize = atoi(optarg);
     92 			if (blksize == 0 || (blksize & (blksize-1))) {
     93 				(void) fprintf(stderr, INVALID_BLKSZ);
     94 				exit(-1);
     95 			}
     96 			break;
     97 		case '?':
     98 			(void) fprintf(stderr, UNKNOWN_OPTION, optopt);
     99 			exit(-1);
    100 		}
    101 	}
    102 	if (argc - optind != 2) {
    103 		(void) fprintf(stderr, MISS_FILES);
    104 		exit(-1);
    105 	}
    106 
    107 	setup_infile(argv[optind]);
    108 	setup_outfile(argv[optind + 1]);
    109 
    110 	if (decompress)
    111 		do_decomp();
    112 	else {
    113 		do_comp(blksize);
    114 		if (doioc) {
    115 			if (ioctl(dstfd, _FIO_COMPRESSED, 0) == -1) {
    116 				(void) fprintf(stderr, FIO_COMP_FAIL,
    117 				    dstfile, strerror(errno));
    118 				exit(-1);
    119 			}
    120 		}
    121 	}
    122 	return (0);
    123 }
    124 
    125 static void
    126 setup_infile(char *file)
    127 {
    128 	int fd;
    129 	void *addr;
    130 	struct stat stbuf;
    131 
    132 	srcfile = file;
    133 
    134 	fd = open(srcfile, O_RDONLY, 0);
    135 	if (fd == -1) {
    136 		(void) fprintf(stderr, CANT_OPEN,
    137 		    srcfile, strerror(errno));
    138 		exit(-1);
    139 	}
    140 
    141 	if (fstat(fd, &stbuf) == -1) {
    142 		(void) fprintf(stderr, STAT_FAIL,
    143 		    srcfile, strerror(errno));
    144 		exit(-1);
    145 	}
    146 	srclen = stbuf.st_size;
    147 
    148 	addr = mmap(0, srclen, PROT_READ, MAP_SHARED, fd, 0);
    149 	if (addr == MAP_FAILED) {
    150 		(void) fprintf(stderr, MMAP_FAIL, srcfile, strerror(errno));
    151 		exit(-1);
    152 	}
    153 	srcaddr = addr;
    154 }
    155 
    156 static void
    157 setup_outfile(char *file)
    158 {
    159 	int fd;
    160 
    161 	dstfile = file;
    162 
    163 	fd = open(dstfile, O_WRONLY | O_CREAT | O_TRUNC,
    164 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    165 	if (fd == -1) {
    166 		(void) fprintf(stderr, OPEN_FAIL, dstfile, strerror(errno));
    167 		exit(-1);
    168 	}
    169 	dstfd = fd;
    170 }
    171 
    172 static void
    173 do_comp(size_t blksize)
    174 {
    175 	struct comphdr *hdr;
    176 	off_t offset;
    177 	size_t blks, dstlen, hlen;
    178 	void *dstbuf;
    179 	int i;
    180 
    181 	blks = ((srclen - 1) / blksize) + 1;
    182 	hlen = offset = sizeof (struct comphdr) + blks * sizeof (uint64_t);
    183 	hdr = malloc(hlen);
    184 	if (hdr == NULL) {
    185 		(void) fprintf(stderr, HDR_ALLOC, hlen);
    186 		exit(-1);
    187 	}
    188 
    189 	hdr->ch_magic = CH_MAGIC_ZLIB;
    190 	hdr->ch_version = CH_VERSION;
    191 	hdr->ch_algorithm = CH_ALG_ZLIB;
    192 	hdr->ch_fsize = srclen;
    193 	hdr->ch_blksize = blksize;
    194 
    195 	dstlen = ZMAXBUF(blksize);
    196 	dstbuf = malloc(dstlen);
    197 	if (dstbuf == NULL) {
    198 		(void) fprintf(stderr, BUF_ALLOC, dstlen);
    199 		exit(-1);
    200 	}
    201 
    202 	if (lseek(dstfd, offset, SEEK_SET) == (off_t)-1) {
    203 		(void) fprintf(stderr, SEEK_ERR,
    204 		    offset, dstfile, strerror(errno));
    205 		exit(-1);
    206 	}
    207 
    208 	for (i = 0; i < blks; i++) {
    209 		ulong_t slen, dlen;
    210 		int ret;
    211 
    212 		hdr->ch_blkmap[i] = offset;
    213 		slen = MIN(srclen, blksize);
    214 		dlen = dstlen;
    215 		ret = compress2(dstbuf, &dlen, (Bytef *)srcaddr, slen, 9);
    216 		if (ret != Z_OK) {
    217 			(void) fprintf(stderr, COMP_ERR, srcfile, ret);
    218 			exit(-1);
    219 		}
    220 
    221 		if (write(dstfd, dstbuf, dlen) != dlen) {
    222 			(void) fprintf(stderr, WRITE_ERR,
    223 			    dlen, dstfile, strerror(errno));
    224 			exit(-1);
    225 		}
    226 
    227 		offset += dlen;
    228 		srclen -= slen;
    229 		srcaddr += slen;
    230 	}
    231 
    232 	if (lseek(dstfd, 0, SEEK_SET) == (off_t)-1) {
    233 		(void) fprintf(stderr, SEEK_ERR,
    234 		    0, dstfile, strerror(errno));
    235 		exit(-1);
    236 	}
    237 
    238 	if (write(dstfd, hdr, hlen) != hlen) {
    239 		(void) fprintf(stderr, WRITE_ERR,
    240 		    hlen, dstfile, strerror(errno));
    241 		exit(-1);
    242 	}
    243 }
    244 
    245 static void
    246 do_decomp()
    247 {
    248 	struct comphdr *hdr;
    249 	size_t blks, blksize;
    250 	void *dstbuf;
    251 	int i;
    252 	ulong_t slen, dlen;
    253 	int ret;
    254 
    255 	hdr = (struct comphdr *)(void *)srcaddr;
    256 	if (hdr->ch_magic != CH_MAGIC_ZLIB) {
    257 		(void) fprintf(stderr, BAD_MAGIC,
    258 		    srcfile, (uint64_t)hdr->ch_magic, CH_MAGIC_ZLIB);
    259 		exit(-1);
    260 	}
    261 	if (hdr->ch_version != CH_VERSION) {
    262 		(void) fprintf(stderr, BAD_VERS,
    263 		    srcfile, (uint64_t)hdr->ch_version, CH_VERSION);
    264 		exit(-1);
    265 	}
    266 	if (hdr->ch_algorithm != CH_ALG_ZLIB) {
    267 		(void) fprintf(stderr, BAD_ALG,
    268 		    srcfile, (uint64_t)hdr->ch_algorithm, CH_ALG_ZLIB);
    269 		exit(-1);
    270 	}
    271 
    272 	blksize = hdr->ch_blksize;
    273 	dstbuf = malloc(blksize);
    274 	if (dstbuf == NULL) {
    275 		(void) fprintf(stderr, HDR_ALLOC, blksize);
    276 		exit(-1);
    277 	}
    278 
    279 	blks = (hdr->ch_fsize - 1) / blksize;
    280 	srcaddr += hdr->ch_blkmap[0];
    281 	for (i = 0; i < blks; i++) {
    282 		dlen = blksize;
    283 		slen = hdr->ch_blkmap[i + 1] - hdr->ch_blkmap[i];
    284 		ret = uncompress(dstbuf, &dlen, (Bytef *)srcaddr, slen);
    285 		if (ret != Z_OK) {
    286 			(void) fprintf(stderr, DECOMP_ERR, srcfile, ret);
    287 			exit(-1);
    288 		}
    289 
    290 		if (dlen != blksize) {
    291 			(void) fprintf(stderr, CORRUPT, srcfile);
    292 			exit(-1);
    293 		}
    294 		if (write(dstfd, dstbuf, dlen) != dlen) {
    295 			(void) fprintf(stderr, WRITE_ERR,
    296 			    dlen, dstfile, strerror(errno));
    297 			exit(-1);
    298 		}
    299 		srcaddr += slen;
    300 	}
    301 
    302 	dlen = blksize;
    303 	slen = hdr->ch_fsize - hdr->ch_blkmap[i];
    304 	if ((ret = uncompress(dstbuf, &dlen, (Bytef *)srcaddr, slen)) != Z_OK) {
    305 		(void) fprintf(stderr, DECOMP_ERR, dstfile, ret);
    306 		exit(-1);
    307 	}
    308 
    309 	if (write(dstfd, dstbuf, dlen) != dlen) {
    310 		(void) fprintf(stderr, WRITE_ERR,
    311 		    dlen, dstfile, strerror(errno));
    312 		exit(-1);
    313 	}
    314 }
    315