kgzcmp.c revision 112047
16059Samurai/* 26059Samurai * Copyright (c) 1999 Global Technology Associates, Inc. 36059Samurai * All rights reserved. 46059Samurai * 56059Samurai * Redistribution and use in source and binary forms, with or without 66059Samurai * modification, are permitted provided that the following conditions 76059Samurai * are met: 86059Samurai * 1. Redistributions of source code must retain the above copyright 96059Samurai * notice, this list of conditions and the following disclaimer. 106059Samurai * 2. Redistributions in binary form must reproduce the above copyright 116059Samurai * notice, this list of conditions and the following disclaimer in the 126059Samurai * documentation and/or other materials provided with the distribution. 136059Samurai * 146059Samurai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 156059Samurai * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166059Samurai * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 176059Samurai * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 186059Samurai * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 196059Samurai * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 2021673Sjkh * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 218857Srgrimes * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 226059Samurai * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 236059Samurai * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 246059Samurai * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 256059Samurai * 266059Samurai * $FreeBSD: head/usr.sbin/kgzip/kgzcmp.c 112047 2003-03-09 21:39:52Z ru $ 276059Samurai */ 2811336Samurai 296059Samurai#include <sys/types.h> 306059Samurai#include <sys/stat.h> 316059Samurai#include <sys/wait.h> 326059Samurai 336059Samurai#include <err.h> 346059Samurai#include <fcntl.h> 3518786Sjkh#include <stdio.h> 366059Samurai#include <stdlib.h> 376059Samurai#include <unistd.h> 3820365Sjkh 3920365Sjkh#include <a.out.h> 406059Samurai 416059Samurai#include "aouthdr.h" 426059Samurai#include "elfhdr.h" 4313389Sphk#include "kgzip.h" 446059Samurai 456059Samuraistatic void mk_data(const struct iodesc *i, const struct iodesc *, 466059Samurai struct kgz_hdr *, size_t); 476735Samuraistatic int ld_elf(const struct iodesc *, const struct iodesc *, 487001Samurai struct kgz_hdr *, const Elf32_Ehdr *); 4913389Sphkstatic int ld_aout(const struct iodesc *, const struct iodesc *, 5013389Sphk struct kgz_hdr *, const struct exec *); 5120365Sjkh 526059Samurai/* 536764Samurai * Compress executable and output it in relocatable object format. 549410Sasami */ 556764Samuraivoid 566735Samuraikgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) 576735Samurai{ 586735Samurai struct iodesc idi, ido; 596735Samurai 606735Samurai if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) 616735Samurai err(1, "%s", idi.fname); 626059Samurai if ((ido.fd = open(ido.fname = f2, O_CREAT | O_TRUNC | O_WRONLY, 636059Samurai 0666)) == -1) 646059Samurai err(1, "%s", ido.fname); 656059Samurai kh->ident[0] = KGZ_ID0; 666059Samurai kh->ident[1] = KGZ_ID1; 6718885Sjkh kh->ident[2] = KGZ_ID2; 686059Samurai kh->ident[3] = KGZ_ID3; 696059Samurai mk_data(&idi, &ido, kh, 706059Samurai (format == F_AOUT ? sizeof(struct kgz_aouthdr0) : 7110528Samurai sizeof(struct kgz_elfhdr)) + 726059Samurai sizeof(struct kgz_hdr)); 736059Samurai kh->dload &= 0xffffff; 746059Samurai kh->entry &= 0xffffff; 7514418Sache if (format == F_AOUT) { 7613379Sphk struct kgz_aouthdr0 ahdr0 = aouthdr0; 7720813Sjkh struct kgz_aouthdr1 ahdr1 = aouthdr1; 786059Samurai unsigned x = (sizeof(struct kgz_hdr) + kh->nsize) & (16 - 1); 7911336Samurai if (x) { 806059Samurai x = 16 - x; 816059Samurai xzero(&ido, x); 826059Samurai } 836059Samurai xwrite(&ido, &ahdr1, sizeof(ahdr1)); 846059Samurai ahdr0.a.a_data += kh->nsize + x; 856059Samurai xseek(&ido, 0); 866059Samurai xwrite(&ido, &ahdr0, sizeof(ahdr0)); 876059Samurai } else { 886059Samurai struct kgz_elfhdr ehdr = elfhdr; 896059Samurai ehdr.st[KGZ_ST_KGZ_NDATA].st_size = kh->nsize; 906059Samurai ehdr.sh[KGZ_SH_DATA].sh_size += kh->nsize; 916059Samurai xseek(&ido, 0); 926059Samurai xwrite(&ido, &ehdr, sizeof(ehdr)); 936059Samurai } 946059Samurai xwrite(&ido, kh, sizeof(*kh)); 956059Samurai xclose(&ido); 966059Samurai xclose(&idi); 976059Samurai} 986059Samurai 996735Samurai/* 1006059Samurai * Make encoded (compressed) data. 1016059Samurai */ 1026059Samuraistatic void 1036059Samuraimk_data(const struct iodesc * idi, const struct iodesc * ido, 1046059Samurai struct kgz_hdr * kh, size_t off) 1056059Samurai{ 10610528Samurai union { 10710528Samurai struct exec ex; 10810528Samurai Elf32_Ehdr ee; 1096059Samurai } hdr; 1106059Samurai struct stat sb; 1116059Samurai struct iodesc idp; 1126059Samurai int fd[2]; 1136059Samurai pid_t pid; 1146059Samurai size_t n; 1156735Samurai int fmt, status, e; 11610528Samurai 1176059Samurai n = xread(idi, &hdr, sizeof(hdr), 0); 1186059Samurai fmt = 0; 1196735Samurai if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) 1206059Samurai fmt = F_ELF; 1216059Samurai else if (n >= sizeof(hdr.ex) && N_GETMAGIC(hdr.ex) == ZMAGIC) 1226059Samurai fmt = F_AOUT; 1236059Samurai if (!fmt) 12410528Samurai errx(1, "%s: Format not supported", idi->fname); 1256059Samurai xseek(ido, off); 1266059Samurai if (pipe(fd)) 1276059Samurai err(1, NULL); 1286059Samurai switch (pid = fork()) { 1296059Samurai case -1: 1306059Samurai err(1, NULL); 1316059Samurai case 0: 1326059Samurai close(fd[1]); 1336059Samurai dup2(fd[0], STDIN_FILENO); 1346059Samurai close(fd[0]); 1356735Samurai close(idi->fd); 1366059Samurai dup2(ido->fd, STDOUT_FILENO); 1376059Samurai close(ido->fd); 1386059Samurai execlp("gzip", "gzip", "-9n", (char *)NULL); 1396059Samurai warn(NULL); 1406059Samurai _exit(1); 1416059Samurai default: 1426059Samurai close(fd[0]); 14310528Samurai idp.fname = "(pipe)"; 1446059Samurai idp.fd = fd[1]; 1456059Samurai e = fmt == F_ELF ? ld_elf(idi, &idp, kh, &hdr.ee) : 1466059Samurai fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1; 1476059Samurai close(fd[1]); 1486059Samurai if ((pid = waitpid(pid, &status, 0)) == -1) 1496059Samurai err(1, NULL); 1506735Samurai if (WIFSIGNALED(status) || WEXITSTATUS(status)) 15110528Samurai exit(1); 15210528Samurai } 15310528Samurai if (e) 15410528Samurai errx(1, "%s: Invalid format", idi->fname); 15510528Samurai if (fstat(ido->fd, &sb)) 15610528Samurai err(1, "%s", ido->fname); 15710528Samurai kh->nsize = sb.st_size - off; 15810528Samurai} 1596059Samurai 1606059Samurai/* 16111336Samurai * "Load" an ELF-format executable. 1626059Samurai */ 16320813Sjkhstatic int 16420813Sjkhld_elf(const struct iodesc * idi, const struct iodesc * ido, 16511336Samurai struct kgz_hdr * kh, const Elf32_Ehdr * e) 16611336Samurai{ 1676059Samurai Elf32_Phdr p; 16815738Sphk size_t load, addr, n; 1696059Samurai unsigned x, i; 1706059Samurai 1716059Samurai load = addr = n = 0; 17210528Samurai for (x = i = 0; i < e->e_phnum; i++) { 1736059Samurai if (xread(idi, &p, sizeof(p), 1746059Samurai e->e_phoff + i * e->e_phentsize) != e->e_phentsize) 1756059Samurai return -1; 1766059Samurai if (p.p_type != PT_LOAD) 1776059Samurai continue; 17814930Sache if (!x) 17914930Sache load = addr = p.p_vaddr; 1806059Samurai else { 18117044Sache if (p.p_vaddr < addr) 18217044Sache return -1; 18317044Sache n = p.p_vaddr - addr; 18417044Sache if (n) { 18517044Sache xzero(ido, n); 18620813Sjkh addr += n; 18720813Sjkh } 18820813Sjkh } 18920813Sjkh if (p.p_memsz < p.p_filesz) 19020813Sjkh return -1; 19120813Sjkh n = p.p_memsz - p.p_filesz; 19220813Sjkh xcopy(idi, ido, p.p_filesz, p.p_offset); 19320813Sjkh addr += p.p_filesz; 1946059Samurai x++; 1956059Samurai } 1966059Samurai if (!x) 19714930Sache return -1; 19814930Sache kh->dload = load; 1996059Samurai kh->dsize = addr - load; 20020813Sjkh kh->isize = kh->dsize + n; 20120813Sjkh kh->entry = e->e_entry; 20220813Sjkh return 0; 20320813Sjkh} 20420813Sjkh 20520813Sjkh/* 20620813Sjkh * "Load" an a.out-format executable. 20720813Sjkh */ 20820813Sjkhstatic int 2096059Samuraild_aout(const struct iodesc * idi, const struct iodesc * ido, 2106059Samurai struct kgz_hdr * kh, const struct exec * a) 21110528Samurai{ 21210528Samurai size_t load, addr; 21310528Samurai 21410528Samurai load = addr = N_TXTADDR(*a); 21510528Samurai xcopy(idi, ido, a->a_text, N_TXTOFF(*a)); 21610528Samurai addr += a->a_text; 21710528Samurai if (N_DATADDR(*a) != addr) 21810528Samurai return -1; 21910528Samurai xcopy(idi, ido, a->a_data, N_DATOFF(*a)); 22010528Samurai addr += a->a_data; 22110528Samurai kh->dload = load; 22210528Samurai kh->dsize = addr - load; 22310528Samurai kh->isize = kh->dsize + a->a_bss; 22410528Samurai kh->entry = a->a_entry; 22510528Samurai return 0; 22610528Samurai} 22710528Samurai