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 /*
22*1d7f3fadSKrishnendu 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;
69986fd29aSsetje char 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
189*1d7f3fadSKrishnendu 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;
256*1d7f3fadSKrishnendu Sadhukhan - Sun Microsystems if (hdr->ch_magic != CH_MAGIC_ZLIB) {
257986fd29aSsetje (void) fprintf(stderr, BAD_MAGIC,
258*1d7f3fadSKrishnendu 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