1986fd29aSsetje /*
2986fd29aSsetje  * CDDL HEADER START
3986fd29aSsetje  *
4986fd29aSsetje  * The contents of this file are subject to the terms of the
5986fd29aSsetje  * Common Development and Distribution License (the "License").
6986fd29aSsetje  * You may not use this file except in compliance with the License.
7986fd29aSsetje  *
8986fd29aSsetje  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9986fd29aSsetje  * or http://www.opensolaris.org/os/licensing.
10986fd29aSsetje  * See the License for the specific language governing permissions
11986fd29aSsetje  * and limitations under the License.
12986fd29aSsetje  *
13986fd29aSsetje  * When distributing Covered Code, include this CDDL HEADER in each
14986fd29aSsetje  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15986fd29aSsetje  * If applicable, add the following below this CDDL HEADER, with the
16986fd29aSsetje  * fields enclosed by brackets "[]" replaced with your own identifying
17986fd29aSsetje  * information: Portions Copyright [yyyy] [name of copyright owner]
18986fd29aSsetje  *
19986fd29aSsetje  * CDDL HEADER END
20986fd29aSsetje  */
21986fd29aSsetje /*
221d7f3fadSKrishnendu Sadhukhan - Sun Microsystems  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23986fd29aSsetje  * Use is subject to license terms.
24986fd29aSsetje  */
25986fd29aSsetje 
26986fd29aSsetje /*
27986fd29aSsetje  * fiocompress - a utility to compress files with a filesystem.
28986fd29aSsetje  * Used to build compressed boot archives to reduce memory
29986fd29aSsetje  * requirements for booting.
30986fd29aSsetje  */
31986fd29aSsetje 
32986fd29aSsetje #include <stdio.h>
33986fd29aSsetje #include <errno.h>
34986fd29aSsetje #include <stdlib.h>
35986fd29aSsetje #include <fcntl.h>
36986fd29aSsetje #include <sys/types.h>
37986fd29aSsetje #include <sys/stat.h>
38986fd29aSsetje #include <sys/mman.h>
39986fd29aSsetje #include <unistd.h>
40986fd29aSsetje #include <utility.h>
41986fd29aSsetje #include <zlib.h>
42986fd29aSsetje 
43986fd29aSsetje #include <sys/filio.h>
44986fd29aSsetje #include <sys/fs/decomp.h>
45986fd29aSsetje 
46986fd29aSsetje #include "message.h"
47986fd29aSsetje 
48986fd29aSsetje static void	setup_infile(char *);
49986fd29aSsetje static void	setup_outfile(char *);
50986fd29aSsetje static void	do_comp(size_t);
51986fd29aSsetje static void	do_decomp(void);
52986fd29aSsetje 
53986fd29aSsetje static caddr_t	srcaddr;
54986fd29aSsetje static size_t	srclen;
55986fd29aSsetje 
56986fd29aSsetje static int	dstfd;
57986fd29aSsetje 
58986fd29aSsetje static char	*srcfile;
59986fd29aSsetje static char	*dstfile;
60986fd29aSsetje 
61986fd29aSsetje 
62986fd29aSsetje int
main(int argc,char ** argv)63986fd29aSsetje main(int argc, char **argv)
64986fd29aSsetje {
65986fd29aSsetje 	int compress = 0;
66986fd29aSsetje 	int decompress = 0;
67986fd29aSsetje 	int doioc = 0;
68986fd29aSsetje 	size_t	blksize = 8192;
69*ef150c2bSRichard Lowe 	int c;
70986fd29aSsetje 
71986fd29aSsetje 	while ((c = getopt(argc, argv, "mcdb:")) != -1) {
72986fd29aSsetje 		switch (c) {
73986fd29aSsetje 		case 'm':
74986fd29aSsetje 			doioc++;
75986fd29aSsetje 			break;
76986fd29aSsetje 		case 'c':
77986fd29aSsetje 			if (decompress) {
78986fd29aSsetje 				(void) fprintf(stderr, OPT_DC_EXCL);
79986fd29aSsetje 				exit(-1);
80986fd29aSsetje 			}
81986fd29aSsetje 			compress = 1;
82986fd29aSsetje 			break;
83986fd29aSsetje 		case 'd':
84986fd29aSsetje 			if (compress) {
85986fd29aSsetje 				(void) fprintf(stderr, OPT_DC_EXCL);
86986fd29aSsetje 				exit(-1);
87986fd29aSsetje 			}
88986fd29aSsetje 			decompress = 1;
89986fd29aSsetje 			break;
90986fd29aSsetje 		case 'b':
91986fd29aSsetje 			blksize = atoi(optarg);
92986fd29aSsetje 			if (blksize == 0 || (blksize & (blksize-1))) {
93986fd29aSsetje 				(void) fprintf(stderr, INVALID_BLKSZ);
94986fd29aSsetje 				exit(-1);
95986fd29aSsetje 			}
96986fd29aSsetje 			break;
97986fd29aSsetje 		case '?':
98986fd29aSsetje 			(void) fprintf(stderr, UNKNOWN_OPTION, optopt);
99986fd29aSsetje 			exit(-1);
100986fd29aSsetje 		}
101986fd29aSsetje 	}
102986fd29aSsetje 	if (argc - optind != 2) {
103986fd29aSsetje 		(void) fprintf(stderr, MISS_FILES);
104986fd29aSsetje 		exit(-1);
105986fd29aSsetje 	}
106986fd29aSsetje 
107986fd29aSsetje 	setup_infile(argv[optind]);
108986fd29aSsetje 	setup_outfile(argv[optind + 1]);
109986fd29aSsetje 
110986fd29aSsetje 	if (decompress)
111986fd29aSsetje 		do_decomp();
112986fd29aSsetje 	else {
113986fd29aSsetje 		do_comp(blksize);
114986fd29aSsetje 		if (doioc) {
115986fd29aSsetje 			if (ioctl(dstfd, _FIO_COMPRESSED, 0) == -1) {
116986fd29aSsetje 				(void) fprintf(stderr, FIO_COMP_FAIL,
117986fd29aSsetje 				    dstfile, strerror(errno));
118986fd29aSsetje 				exit(-1);
119986fd29aSsetje 			}
120986fd29aSsetje 		}
121986fd29aSsetje 	}
122986fd29aSsetje 	return (0);
123986fd29aSsetje }
124986fd29aSsetje 
125986fd29aSsetje static void
setup_infile(char * file)126986fd29aSsetje setup_infile(char *file)
127986fd29aSsetje {
128986fd29aSsetje 	int fd;
129986fd29aSsetje 	void *addr;
130986fd29aSsetje 	struct stat stbuf;
131986fd29aSsetje 
132986fd29aSsetje 	srcfile = file;
133986fd29aSsetje 
134986fd29aSsetje 	fd = open(srcfile, O_RDONLY, 0);
135986fd29aSsetje 	if (fd == -1) {
136986fd29aSsetje 		(void) fprintf(stderr, CANT_OPEN,
137986fd29aSsetje 		    srcfile, strerror(errno));
138986fd29aSsetje 		exit(-1);
139986fd29aSsetje 	}
140986fd29aSsetje 
141986fd29aSsetje 	if (fstat(fd, &stbuf) == -1) {
142986fd29aSsetje 		(void) fprintf(stderr, STAT_FAIL,
143986fd29aSsetje 		    srcfile, strerror(errno));
144986fd29aSsetje 		exit(-1);
145986fd29aSsetje 	}
146986fd29aSsetje 	srclen = stbuf.st_size;
147986fd29aSsetje 
148986fd29aSsetje 	addr = mmap(0, srclen, PROT_READ, MAP_SHARED, fd, 0);
149986fd29aSsetje 	if (addr == MAP_FAILED) {
150986fd29aSsetje 		(void) fprintf(stderr, MMAP_FAIL, srcfile, strerror(errno));
151986fd29aSsetje 		exit(-1);
152986fd29aSsetje 	}
153986fd29aSsetje 	srcaddr = addr;
154986fd29aSsetje }
155986fd29aSsetje 
156986fd29aSsetje static void
setup_outfile(char * file)157986fd29aSsetje setup_outfile(char *file)
158986fd29aSsetje {
159986fd29aSsetje 	int fd;
160986fd29aSsetje 
161986fd29aSsetje 	dstfile = file;
162986fd29aSsetje 
163986fd29aSsetje 	fd = open(dstfile, O_WRONLY | O_CREAT | O_TRUNC,
164986fd29aSsetje 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
165986fd29aSsetje 	if (fd == -1) {
166986fd29aSsetje 		(void) fprintf(stderr, OPEN_FAIL, dstfile, strerror(errno));
167986fd29aSsetje 		exit(-1);
168986fd29aSsetje 	}
169986fd29aSsetje 	dstfd = fd;
170986fd29aSsetje }
171986fd29aSsetje 
172986fd29aSsetje static void
do_comp(size_t blksize)173986fd29aSsetje do_comp(size_t blksize)
174986fd29aSsetje {
175986fd29aSsetje 	struct comphdr *hdr;
176986fd29aSsetje 	off_t offset;
177986fd29aSsetje 	size_t blks, dstlen, hlen;
178986fd29aSsetje 	void *dstbuf;
179986fd29aSsetje 	int i;
180986fd29aSsetje 
181986fd29aSsetje 	blks = ((srclen - 1) / blksize) + 1;
182986fd29aSsetje 	hlen = offset = sizeof (struct comphdr) + blks * sizeof (uint64_t);
183986fd29aSsetje 	hdr = malloc(hlen);
184986fd29aSsetje 	if (hdr == NULL) {
185986fd29aSsetje 		(void) fprintf(stderr, HDR_ALLOC, hlen);
186986fd29aSsetje 		exit(-1);
187986fd29aSsetje 	}
188986fd29aSsetje 
1891d7f3fadSKrishnendu Sadhukhan - Sun Microsystems 	hdr->ch_magic = CH_MAGIC_ZLIB;
190986fd29aSsetje 	hdr->ch_version = CH_VERSION;
191986fd29aSsetje 	hdr->ch_algorithm = CH_ALG_ZLIB;
192986fd29aSsetje 	hdr->ch_fsize = srclen;
193986fd29aSsetje 	hdr->ch_blksize = blksize;
194986fd29aSsetje 
195986fd29aSsetje 	dstlen = ZMAXBUF(blksize);
196986fd29aSsetje 	dstbuf = malloc(dstlen);
197986fd29aSsetje 	if (dstbuf == NULL) {
198986fd29aSsetje 		(void) fprintf(stderr, BUF_ALLOC, dstlen);
199986fd29aSsetje 		exit(-1);
200986fd29aSsetje 	}
201986fd29aSsetje 
202986fd29aSsetje 	if (lseek(dstfd, offset, SEEK_SET) == (off_t)-1) {
203986fd29aSsetje 		(void) fprintf(stderr, SEEK_ERR,
204986fd29aSsetje 		    offset, dstfile, strerror(errno));
205986fd29aSsetje 		exit(-1);
206986fd29aSsetje 	}
207986fd29aSsetje 
208986fd29aSsetje 	for (i = 0; i < blks; i++) {
209986fd29aSsetje 		ulong_t slen, dlen;
210986fd29aSsetje 		int ret;
211986fd29aSsetje 
212986fd29aSsetje 		hdr->ch_blkmap[i] = offset;
213986fd29aSsetje 		slen = MIN(srclen, blksize);
214986fd29aSsetje 		dlen = dstlen;
215986fd29aSsetje 		ret = compress2(dstbuf, &dlen, (Bytef *)srcaddr, slen, 9);
216986fd29aSsetje 		if (ret != Z_OK) {
217986fd29aSsetje 			(void) fprintf(stderr, COMP_ERR, srcfile, ret);
218986fd29aSsetje 			exit(-1);
219986fd29aSsetje 		}
220986fd29aSsetje 
221986fd29aSsetje 		if (write(dstfd, dstbuf, dlen) != dlen) {
222986fd29aSsetje 			(void) fprintf(stderr, WRITE_ERR,
223986fd29aSsetje 			    dlen, dstfile, strerror(errno));
224986fd29aSsetje 			exit(-1);
225986fd29aSsetje 		}
226986fd29aSsetje 
227986fd29aSsetje 		offset += dlen;
228986fd29aSsetje 		srclen -= slen;
229986fd29aSsetje 		srcaddr += slen;
230986fd29aSsetje 	}
231986fd29aSsetje 
232986fd29aSsetje 	if (lseek(dstfd, 0, SEEK_SET) == (off_t)-1) {
233986fd29aSsetje 		(void) fprintf(stderr, SEEK_ERR,
234986fd29aSsetje 		    0, dstfile, strerror(errno));
235986fd29aSsetje 		exit(-1);
236986fd29aSsetje 	}
237986fd29aSsetje 
238986fd29aSsetje 	if (write(dstfd, hdr, hlen) != hlen) {
239986fd29aSsetje 		(void) fprintf(stderr, WRITE_ERR,
240986fd29aSsetje 		    hlen, dstfile, strerror(errno));
241986fd29aSsetje 		exit(-1);
242986fd29aSsetje 	}
243986fd29aSsetje }
244986fd29aSsetje 
245986fd29aSsetje static void
do_decomp()246986fd29aSsetje do_decomp()
247986fd29aSsetje {
248986fd29aSsetje 	struct comphdr *hdr;
249986fd29aSsetje 	size_t blks, blksize;
250986fd29aSsetje 	void *dstbuf;
251986fd29aSsetje 	int i;
252986fd29aSsetje 	ulong_t slen, dlen;
253986fd29aSsetje 	int ret;
254986fd29aSsetje 
255986fd29aSsetje 	hdr = (struct comphdr *)(void *)srcaddr;
2561d7f3fadSKrishnendu Sadhukhan - Sun Microsystems 	if (hdr->ch_magic != CH_MAGIC_ZLIB) {
257986fd29aSsetje 		(void) fprintf(stderr, BAD_MAGIC,
2581d7f3fadSKrishnendu Sadhukhan - Sun Microsystems 		    srcfile, (uint64_t)hdr->ch_magic, CH_MAGIC_ZLIB);
259986fd29aSsetje 		exit(-1);
260986fd29aSsetje 	}
261986fd29aSsetje 	if (hdr->ch_version != CH_VERSION) {
262986fd29aSsetje 		(void) fprintf(stderr, BAD_VERS,
263986fd29aSsetje 		    srcfile, (uint64_t)hdr->ch_version, CH_VERSION);
264986fd29aSsetje 		exit(-1);
265986fd29aSsetje 	}
266986fd29aSsetje 	if (hdr->ch_algorithm != CH_ALG_ZLIB) {
267986fd29aSsetje 		(void) fprintf(stderr, BAD_ALG,
268986fd29aSsetje 		    srcfile, (uint64_t)hdr->ch_algorithm, CH_ALG_ZLIB);
269986fd29aSsetje 		exit(-1);
270986fd29aSsetje 	}
271986fd29aSsetje 
272986fd29aSsetje 	blksize = hdr->ch_blksize;
273986fd29aSsetje 	dstbuf = malloc(blksize);
274986fd29aSsetje 	if (dstbuf == NULL) {
275986fd29aSsetje 		(void) fprintf(stderr, HDR_ALLOC, blksize);
276986fd29aSsetje 		exit(-1);
277986fd29aSsetje 	}
278986fd29aSsetje 
279986fd29aSsetje 	blks = (hdr->ch_fsize - 1) / blksize;
280986fd29aSsetje 	srcaddr += hdr->ch_blkmap[0];
281986fd29aSsetje 	for (i = 0; i < blks; i++) {
282986fd29aSsetje 		dlen = blksize;
283986fd29aSsetje 		slen = hdr->ch_blkmap[i + 1] - hdr->ch_blkmap[i];
284986fd29aSsetje 		ret = uncompress(dstbuf, &dlen, (Bytef *)srcaddr, slen);
285986fd29aSsetje 		if (ret != Z_OK) {
286986fd29aSsetje 			(void) fprintf(stderr, DECOMP_ERR, srcfile, ret);
287986fd29aSsetje 			exit(-1);
288986fd29aSsetje 		}
289986fd29aSsetje 
290986fd29aSsetje 		if (dlen != blksize) {
291986fd29aSsetje 			(void) fprintf(stderr, CORRUPT, srcfile);
292986fd29aSsetje 			exit(-1);
293986fd29aSsetje 		}
294986fd29aSsetje 		if (write(dstfd, dstbuf, dlen) != dlen) {
295986fd29aSsetje 			(void) fprintf(stderr, WRITE_ERR,
296986fd29aSsetje 			    dlen, dstfile, strerror(errno));
297986fd29aSsetje 			exit(-1);
298986fd29aSsetje 		}
299986fd29aSsetje 		srcaddr += slen;
300986fd29aSsetje 	}
301986fd29aSsetje 
302986fd29aSsetje 	dlen = blksize;
303986fd29aSsetje 	slen = hdr->ch_fsize - hdr->ch_blkmap[i];
304986fd29aSsetje 	if ((ret = uncompress(dstbuf, &dlen, (Bytef *)srcaddr, slen)) != Z_OK) {
305986fd29aSsetje 		(void) fprintf(stderr, DECOMP_ERR, dstfile, ret);
306986fd29aSsetje 		exit(-1);
307986fd29aSsetje 	}
308986fd29aSsetje 
309986fd29aSsetje 	if (write(dstfd, dstbuf, dlen) != dlen) {
310986fd29aSsetje 		(void) fprintf(stderr, WRITE_ERR,
311986fd29aSsetje 		    dlen, dstfile, strerror(errno));
312986fd29aSsetje 		exit(-1);
313986fd29aSsetje 	}
314986fd29aSsetje }
315