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