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 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 char 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 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 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 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 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