kgzcmp.c revision 112089
1/* 2 * Copyright (c) 1999 Global Technology Associates, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 19 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: head/usr.sbin/kgzip/kgzcmp.c 112089 2003-03-11 11:45:43Z ru $ 27 */ 28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <sys/wait.h> 32 33#include <err.h> 34#include <fcntl.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <unistd.h> 38 39#include "i386_a.out.h" 40 41#include "aouthdr.h" 42#include "elfhdr.h" 43#include "endian.h" 44#include "kgzip.h" 45 46static void mk_data(const struct iodesc *i, const struct iodesc *, 47 struct kgz_hdr *, size_t); 48static int ld_elf(const struct iodesc *, const struct iodesc *, 49 struct kgz_hdr *, const Elf32_Ehdr *); 50static int ld_aout(const struct iodesc *, const struct iodesc *, 51 struct kgz_hdr *, const struct i386_exec *); 52 53/* 54 * Compress executable and output it in relocatable object format. 55 */ 56void 57kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) 58{ 59 struct iodesc idi, ido; 60 struct kgz_hdr khle; 61 62 if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) 63 err(1, "%s", idi.fname); 64 if ((ido.fd = open(ido.fname = f2, O_CREAT | O_TRUNC | O_WRONLY, 65 0666)) == -1) 66 err(1, "%s", ido.fname); 67 kh->ident[0] = KGZ_ID0; 68 kh->ident[1] = KGZ_ID1; 69 kh->ident[2] = KGZ_ID2; 70 kh->ident[3] = KGZ_ID3; 71 mk_data(&idi, &ido, kh, 72 (format == F_AOUT ? sizeof(struct kgz_aouthdr0) : 73 sizeof(struct kgz_elfhdr)) + 74 sizeof(struct kgz_hdr)); 75 kh->dload &= 0xffffff; 76 kh->entry &= 0xffffff; 77 if (format == F_AOUT) { 78 struct kgz_aouthdr0 ahdr0 = aouthdr0; 79 struct kgz_aouthdr1 ahdr1 = aouthdr1; 80 unsigned x = (sizeof(struct kgz_hdr) + kh->nsize) & (16 - 1); 81 if (x) { 82 x = 16 - x; 83 xzero(&ido, x); 84 } 85 xwrite(&ido, &ahdr1, sizeof(ahdr1)); 86 ahdr0.a.a_data += kh->nsize + x; 87 xseek(&ido, 0); 88 xwrite(&ido, &ahdr0, sizeof(ahdr0)); 89 } else { 90 struct kgz_elfhdr ehdr = elfhdr; 91 ehdr.st[KGZ_ST_KGZ_NDATA].st_size = HTOLE32(kh->nsize); 92 ehdr.sh[KGZ_SH_DATA].sh_size = 93 HTOLE32(LE32TOH(ehdr.sh[KGZ_SH_DATA].sh_size) + kh->nsize); 94 xseek(&ido, 0); 95 xwrite(&ido, &ehdr, sizeof(ehdr)); 96 } 97 khle = *kh; 98 khle.dload = HTOLE32(khle.dload); 99 khle.dsize = HTOLE32(khle.dsize); 100 khle.isize = HTOLE32(khle.isize); 101 khle.entry = HTOLE32(khle.entry); 102 khle.nsize = HTOLE32(khle.nsize); 103 xwrite(&ido, &khle, sizeof(khle)); 104 xclose(&ido); 105 xclose(&idi); 106} 107 108/* 109 * Make encoded (compressed) data. 110 */ 111static void 112mk_data(const struct iodesc * idi, const struct iodesc * ido, 113 struct kgz_hdr * kh, size_t off) 114{ 115 union { 116 struct i386_exec ex; 117 Elf32_Ehdr ee; 118 } hdr; 119 struct stat sb; 120 struct iodesc idp; 121 int fd[2]; 122 pid_t pid; 123 size_t n; 124 int fmt, status, e; 125 126 n = xread(idi, &hdr, sizeof(hdr), 0); 127 fmt = 0; 128 if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) 129 fmt = F_ELF; 130 else if (n >= sizeof(hdr.ex) && I386_N_GETMAGIC(hdr.ex) == ZMAGIC) 131 fmt = F_AOUT; 132 if (!fmt) 133 errx(1, "%s: Format not supported", idi->fname); 134 xseek(ido, off); 135 if (pipe(fd)) 136 err(1, NULL); 137 switch (pid = fork()) { 138 case -1: 139 err(1, NULL); 140 case 0: 141 close(fd[1]); 142 dup2(fd[0], STDIN_FILENO); 143 close(fd[0]); 144 close(idi->fd); 145 dup2(ido->fd, STDOUT_FILENO); 146 close(ido->fd); 147 execlp("gzip", "gzip", "-9n", (char *)NULL); 148 warn(NULL); 149 _exit(1); 150 default: 151 close(fd[0]); 152 idp.fname = "(pipe)"; 153 idp.fd = fd[1]; 154 e = fmt == F_ELF ? ld_elf(idi, &idp, kh, &hdr.ee) : 155 fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1; 156 close(fd[1]); 157 if ((pid = waitpid(pid, &status, 0)) == -1) 158 err(1, NULL); 159 if (WIFSIGNALED(status) || WEXITSTATUS(status)) 160 exit(1); 161 } 162 if (e) 163 errx(1, "%s: Invalid format", idi->fname); 164 if (fstat(ido->fd, &sb)) 165 err(1, "%s", ido->fname); 166 kh->nsize = sb.st_size - off; 167} 168 169/* 170 * "Load" an ELF-format executable. 171 */ 172static int 173ld_elf(const struct iodesc * idi, const struct iodesc * ido, 174 struct kgz_hdr * kh, const Elf32_Ehdr * e) 175{ 176 Elf32_Phdr p; 177 size_t load, addr, n; 178 unsigned x, i; 179 180 load = addr = n = 0; 181 for (x = i = 0; i < e->e_phnum; i++) { 182 if (xread(idi, &p, sizeof(p), 183 e->e_phoff + i * e->e_phentsize) != e->e_phentsize) 184 return -1; 185 if (p.p_type != PT_LOAD) 186 continue; 187 if (!x) 188 load = addr = p.p_vaddr; 189 else { 190 if (p.p_vaddr < addr) 191 return -1; 192 n = p.p_vaddr - addr; 193 if (n) { 194 xzero(ido, n); 195 addr += n; 196 } 197 } 198 if (p.p_memsz < p.p_filesz) 199 return -1; 200 n = p.p_memsz - p.p_filesz; 201 xcopy(idi, ido, p.p_filesz, p.p_offset); 202 addr += p.p_filesz; 203 x++; 204 } 205 if (!x) 206 return -1; 207 kh->dload = load; 208 kh->dsize = addr - load; 209 kh->isize = kh->dsize + n; 210 kh->entry = e->e_entry; 211 return 0; 212} 213 214/* 215 * "Load" an a.out-format executable. 216 */ 217static int 218ld_aout(const struct iodesc * idi, const struct iodesc * ido, 219 struct kgz_hdr * kh, const struct i386_exec * a) 220{ 221 size_t load, addr; 222 223 load = addr = I386_N_TXTADDR(*a); 224 xcopy(idi, ido, LE32TOH(a->a_text), I386_N_TXTOFF(*a)); 225 addr += LE32TOH(a->a_text); 226 if (I386_N_DATADDR(*a) != addr) 227 return -1; 228 xcopy(idi, ido, LE32TOH(a->a_data), I386_N_DATOFF(*a)); 229 addr += LE32TOH(a->a_data); 230 kh->dload = load; 231 kh->dsize = addr - load; 232 kh->isize = kh->dsize + LE32TOH(a->a_bss); 233 kh->entry = LE32TOH(a->a_entry); 234 return 0; 235} 236