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