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