kgzcmp.c revision 48906
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 * $Id:$ 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 <a.out.h> 40#include <elf.h> 41 42#include "elfhdr.h" 43#include "kgzip.h" 44 45#define KGZOFF (sizeof(struct kgz_elfhdr) + sizeof(struct kgz_hdr)) 46 47#define F_AOUT 1 /* Input format: a.out */ 48#define F_ELF 2 /* Input format: ELF32 */ 49 50static void mk_data(const struct iodesc *i, const struct iodesc *, 51 struct kgz_hdr *); 52static int ld_elf(const struct iodesc *, const struct iodesc *, 53 struct kgz_hdr *, const Elf32_Ehdr *); 54static int ld_aout(const struct iodesc *, const struct iodesc *, 55 struct kgz_hdr *, const struct exec *); 56 57/* 58 * Compress executable and output it in relocatable object format. 59 */ 60void 61kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) 62{ 63 struct iodesc idi, ido; 64 struct kgz_elfhdr ehdr; 65 66 if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) 67 err(1, "%s", idi.fname); 68 if ((ido.fd = open(ido.fname = f2, O_CREAT | O_TRUNC | O_WRONLY, 69 0666)) == -1) 70 err(1, "%s", ido.fname); 71 kh->ident[0] = KGZ_ID0; 72 kh->ident[1] = KGZ_ID1; 73 kh->ident[2] = KGZ_ID2; 74 kh->ident[3] = KGZ_ID3; 75 xseek(&ido, KGZOFF); 76 mk_data(&idi, &ido, kh); 77 kh->dload &= 0xffffff; 78 kh->entry &= 0xffffff; 79 xseek(&ido, 0); 80 ehdr = elfhdr; 81 ehdr.st[KGZ_ST_KGZ_NDATA].st_size = kh->nsize; 82 ehdr.sh[KGZ_SH_DATA].sh_size += kh->nsize; 83 xwrite(&ido, &ehdr, sizeof(ehdr)); 84 xwrite(&ido, kh, sizeof(*kh)); 85 xclose(&ido); 86 xclose(&idi); 87} 88 89/* 90 * Make encoded (compressed) data. 91 */ 92static void 93mk_data(const struct iodesc * idi, const struct iodesc * ido, 94 struct kgz_hdr * kh) 95{ 96 union { 97 struct exec ex; 98 Elf32_Ehdr ee; 99 } hdr; 100 struct stat sb; 101 struct iodesc idp; 102 int fd[2]; 103 pid_t pid; 104 size_t n; 105 int fmt, status, e; 106 107 n = xread(idi, &hdr, sizeof(hdr), 0); 108 fmt = 0; 109 if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) 110 fmt = F_ELF; 111 else if (n >= sizeof(hdr.ex) && N_GETMAGIC(hdr.ex) == ZMAGIC) 112 fmt = F_AOUT; 113 if (!fmt) 114 errx(1, "%s: Format not supported", idi->fname); 115 if (pipe(fd)) 116 err(1, NULL); 117 switch (pid = fork()) { 118 case -1: 119 err(1, NULL); 120 case 0: 121 close(fd[1]); 122 dup2(fd[0], STDIN_FILENO); 123 close(fd[0]); 124 close(idi->fd); 125 dup2(ido->fd, STDOUT_FILENO); 126 close(ido->fd); 127 execlp("gzip", "gzip", "-9", NULL); 128 warn(NULL); 129 _exit(1); 130 default: 131 close(fd[0]); 132 idp.fname = "(pipe)"; 133 idp.fd = fd[1]; 134 e = fmt == F_ELF ? ld_elf(idi, &idp, kh, &hdr.ee) : 135 fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1; 136 close(fd[1]); 137 if ((pid = waitpid(pid, &status, 0)) == -1) 138 err(1, NULL); 139 if (WIFSIGNALED(status) || WEXITSTATUS(status)) 140 exit(1); 141 } 142 if (e) 143 errx(1, "%s: Invalid format", idi->fname); 144 if (fstat(ido->fd, &sb)) 145 err(1, ido->fname); 146 kh->nsize = sb.st_size - KGZOFF; 147} 148 149/* 150 * "Load" an ELF-format executable. 151 */ 152static int 153ld_elf(const struct iodesc * idi, const struct iodesc * ido, 154 struct kgz_hdr * kh, const Elf32_Ehdr * e) 155{ 156 Elf32_Phdr p; 157 size_t load, addr, n; 158 unsigned x, i; 159 160 load = addr = n = 0; 161 for (x = i = 0; i < e->e_phnum; i++) { 162 if (xread(idi, &p, sizeof(p), 163 e->e_phoff + i * e->e_phentsize) != e->e_phentsize) 164 return -1; 165 if (p.p_type != PT_LOAD) 166 continue; 167 if (!x) 168 load = addr = p.p_vaddr; 169 else { 170 if (p.p_vaddr < addr) 171 return -1; 172 n = p.p_vaddr - addr; 173 if (n) { 174 xzero(ido, n); 175 addr += n; 176 } 177 } 178 if (p.p_memsz < p.p_filesz) 179 return -1; 180 n = p.p_memsz - p.p_filesz; 181 xcopy(idi, ido, p.p_filesz, p.p_offset); 182 addr += p.p_filesz; 183 x++; 184 } 185 if (!x) 186 return -1; 187 kh->dload = load; 188 kh->dsize = addr - load; 189 kh->isize = kh->dsize + n; 190 kh->entry = e->e_entry; 191 return 0; 192} 193 194/* 195 * "Load" an a.out-format executable. 196 */ 197static int 198ld_aout(const struct iodesc * idi, const struct iodesc * ido, 199 struct kgz_hdr * kh, const struct exec * a) 200{ 201 size_t load, addr; 202 203 load = addr = N_TXTADDR(*a); 204 xcopy(idi, ido, a->a_text, N_TXTOFF(*a)); 205 addr += a->a_text; 206 if (N_DATADDR(*a) != addr) 207 return -1; 208 xcopy(idi, ido, a->a_data, N_DATOFF(*a)); 209 addr += a->a_data; 210 kh->dload = load; 211 kh->dsize = addr - load; 212 kh->isize = kh->dsize + a->a_bss; 213 kh->entry = a->a_entry; 214 return 0; 215} 216