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
main(int argc,char ** argv)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 int 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
setup_infile(char * file)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
setup_outfile(char * file)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
do_comp(size_t blksize)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
do_decomp()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