1330449Seadler/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 448905Srnordier * Copyright (c) 1999 Global Technology Associates, Inc. 548905Srnordier * All rights reserved. 648905Srnordier * 748905Srnordier * Redistribution and use in source and binary forms, with or without 848905Srnordier * modification, are permitted provided that the following conditions 948905Srnordier * are met: 1048905Srnordier * 1. Redistributions of source code must retain the above copyright 1148905Srnordier * notice, this list of conditions and the following disclaimer. 1248905Srnordier * 2. Redistributions in binary form must reproduce the above copyright 1348905Srnordier * notice, this list of conditions and the following disclaimer in the 1448905Srnordier * documentation and/or other materials provided with the distribution. 1548905Srnordier * 1648905Srnordier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 1748905Srnordier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1848905Srnordier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1948905Srnordier * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 2048905Srnordier * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 2148905Srnordier * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 2248905Srnordier * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 2348905Srnordier * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2448905Srnordier * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 2548905Srnordier * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 2648905Srnordier * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2748905Srnordier * 2850479Speter * $FreeBSD: stable/11/usr.sbin/kgzip/kgzcmp.c 330449 2018-03-05 07:26:05Z eadler $ 2948905Srnordier */ 3048905Srnordier 31130927Sobrien#define _KERNEL 32130927Sobrien#include <sys/param.h> 33130927Sobrien#undef _KERNEL 3448905Srnordier#include <sys/types.h> 3548905Srnordier#include <sys/stat.h> 3648905Srnordier#include <sys/wait.h> 3748905Srnordier 3848905Srnordier#include <err.h> 3948905Srnordier#include <fcntl.h> 4048905Srnordier#include <stdio.h> 4148905Srnordier#include <stdlib.h> 4248905Srnordier#include <unistd.h> 4348905Srnordier 44130927Sobrien#include <a.out.h> 4548905Srnordier 4668313Srnordier#include "aouthdr.h" 4748905Srnordier#include "elfhdr.h" 4848905Srnordier#include "kgzip.h" 4948905Srnordier 5048905Srnordierstatic void mk_data(const struct iodesc *i, const struct iodesc *, 5168313Srnordier struct kgz_hdr *, size_t); 5248905Srnordierstatic int ld_elf(const struct iodesc *, const struct iodesc *, 5348905Srnordier struct kgz_hdr *, const Elf32_Ehdr *); 5448905Srnordierstatic int ld_aout(const struct iodesc *, const struct iodesc *, 55130927Sobrien struct kgz_hdr *, const struct exec *); 5648905Srnordier 5748905Srnordier/* 5848905Srnordier * Compress executable and output it in relocatable object format. 5948905Srnordier */ 6048905Srnordiervoid 6148905Srnordierkgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) 6248905Srnordier{ 6348905Srnordier struct iodesc idi, ido; 64112089Sru struct kgz_hdr khle; 6548905Srnordier 6648905Srnordier if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) 6748905Srnordier err(1, "%s", idi.fname); 6848905Srnordier if ((ido.fd = open(ido.fname = f2, O_CREAT | O_TRUNC | O_WRONLY, 6948905Srnordier 0666)) == -1) 7048905Srnordier err(1, "%s", ido.fname); 7148905Srnordier kh->ident[0] = KGZ_ID0; 7248905Srnordier kh->ident[1] = KGZ_ID1; 7348905Srnordier kh->ident[2] = KGZ_ID2; 7448905Srnordier kh->ident[3] = KGZ_ID3; 7568313Srnordier mk_data(&idi, &ido, kh, 7668313Srnordier (format == F_AOUT ? sizeof(struct kgz_aouthdr0) : 7768313Srnordier sizeof(struct kgz_elfhdr)) + 7868313Srnordier sizeof(struct kgz_hdr)); 7948905Srnordier kh->dload &= 0xffffff; 8048905Srnordier kh->entry &= 0xffffff; 8168313Srnordier if (format == F_AOUT) { 8268313Srnordier struct kgz_aouthdr0 ahdr0 = aouthdr0; 8368313Srnordier struct kgz_aouthdr1 ahdr1 = aouthdr1; 8468313Srnordier unsigned x = (sizeof(struct kgz_hdr) + kh->nsize) & (16 - 1); 8568313Srnordier if (x) { 8668313Srnordier x = 16 - x; 8768313Srnordier xzero(&ido, x); 8868313Srnordier } 8968313Srnordier xwrite(&ido, &ahdr1, sizeof(ahdr1)); 9068313Srnordier ahdr0.a.a_data += kh->nsize + x; 9168313Srnordier xseek(&ido, 0); 9268313Srnordier xwrite(&ido, &ahdr0, sizeof(ahdr0)); 9368313Srnordier } else { 9468313Srnordier struct kgz_elfhdr ehdr = elfhdr; 95130927Sobrien ehdr.st[KGZ_ST_KGZ_NDATA].st_size = htole32(kh->nsize); 96112089Sru ehdr.sh[KGZ_SH_DATA].sh_size = 97130927Sobrien htole32(le32toh(ehdr.sh[KGZ_SH_DATA].sh_size) + kh->nsize); 9868313Srnordier xseek(&ido, 0); 9968313Srnordier xwrite(&ido, &ehdr, sizeof(ehdr)); 10068313Srnordier } 101112089Sru khle = *kh; 102130927Sobrien khle.dload = htole32(khle.dload); 103130927Sobrien khle.dsize = htole32(khle.dsize); 104130927Sobrien khle.isize = htole32(khle.isize); 105130927Sobrien khle.entry = htole32(khle.entry); 106130927Sobrien khle.nsize = htole32(khle.nsize); 107112089Sru xwrite(&ido, &khle, sizeof(khle)); 10848905Srnordier xclose(&ido); 10948905Srnordier xclose(&idi); 11048905Srnordier} 11148905Srnordier 11248905Srnordier/* 11348905Srnordier * Make encoded (compressed) data. 11448905Srnordier */ 11548905Srnordierstatic void 11648905Srnordiermk_data(const struct iodesc * idi, const struct iodesc * ido, 11768313Srnordier struct kgz_hdr * kh, size_t off) 11848905Srnordier{ 11948905Srnordier union { 120130927Sobrien struct exec ex; 12148905Srnordier Elf32_Ehdr ee; 12248905Srnordier } hdr; 12348905Srnordier struct stat sb; 12448905Srnordier struct iodesc idp; 12548905Srnordier int fd[2]; 12648905Srnordier pid_t pid; 12748905Srnordier size_t n; 12848905Srnordier int fmt, status, e; 12948905Srnordier 13048905Srnordier n = xread(idi, &hdr, sizeof(hdr), 0); 13148905Srnordier fmt = 0; 13248905Srnordier if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) 13348905Srnordier fmt = F_ELF; 134130927Sobrien else if (n >= sizeof(hdr.ex) && N_GETMAGIC(hdr.ex) == ZMAGIC) 13548905Srnordier fmt = F_AOUT; 13648905Srnordier if (!fmt) 13748905Srnordier errx(1, "%s: Format not supported", idi->fname); 13868313Srnordier xseek(ido, off); 13948905Srnordier if (pipe(fd)) 14048905Srnordier err(1, NULL); 14148905Srnordier switch (pid = fork()) { 14248905Srnordier case -1: 14348905Srnordier err(1, NULL); 14448905Srnordier case 0: 14548905Srnordier close(fd[1]); 14648905Srnordier dup2(fd[0], STDIN_FILENO); 14748905Srnordier close(fd[0]); 14848905Srnordier close(idi->fd); 14948905Srnordier dup2(ido->fd, STDOUT_FILENO); 15048905Srnordier close(ido->fd); 151112047Sru execlp("gzip", "gzip", "-9n", (char *)NULL); 15248905Srnordier warn(NULL); 15348905Srnordier _exit(1); 15448905Srnordier default: 15548905Srnordier close(fd[0]); 15648905Srnordier idp.fname = "(pipe)"; 15748905Srnordier idp.fd = fd[1]; 15848905Srnordier e = fmt == F_ELF ? ld_elf(idi, &idp, kh, &hdr.ee) : 15948905Srnordier fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1; 16048905Srnordier close(fd[1]); 16148905Srnordier if ((pid = waitpid(pid, &status, 0)) == -1) 16248905Srnordier err(1, NULL); 16348905Srnordier if (WIFSIGNALED(status) || WEXITSTATUS(status)) 16448905Srnordier exit(1); 16548905Srnordier } 16648905Srnordier if (e) 16748905Srnordier errx(1, "%s: Invalid format", idi->fname); 16848905Srnordier if (fstat(ido->fd, &sb)) 16962986Skris err(1, "%s", ido->fname); 17068313Srnordier kh->nsize = sb.st_size - off; 17148905Srnordier} 17248905Srnordier 17348905Srnordier/* 17448905Srnordier * "Load" an ELF-format executable. 17548905Srnordier */ 17648905Srnordierstatic int 17748905Srnordierld_elf(const struct iodesc * idi, const struct iodesc * ido, 17848905Srnordier struct kgz_hdr * kh, const Elf32_Ehdr * e) 17948905Srnordier{ 18048905Srnordier Elf32_Phdr p; 18148905Srnordier size_t load, addr, n; 18248905Srnordier unsigned x, i; 18348905Srnordier 18448905Srnordier load = addr = n = 0; 18548905Srnordier for (x = i = 0; i < e->e_phnum; i++) { 18648905Srnordier if (xread(idi, &p, sizeof(p), 18748905Srnordier e->e_phoff + i * e->e_phentsize) != e->e_phentsize) 18848905Srnordier return -1; 18948905Srnordier if (p.p_type != PT_LOAD) 19048905Srnordier continue; 19148905Srnordier if (!x) 19248905Srnordier load = addr = p.p_vaddr; 19348905Srnordier else { 19448905Srnordier if (p.p_vaddr < addr) 19548905Srnordier return -1; 19648905Srnordier n = p.p_vaddr - addr; 19748905Srnordier if (n) { 19848905Srnordier xzero(ido, n); 19948905Srnordier addr += n; 20048905Srnordier } 20148905Srnordier } 20248905Srnordier if (p.p_memsz < p.p_filesz) 20348905Srnordier return -1; 20448905Srnordier n = p.p_memsz - p.p_filesz; 20548905Srnordier xcopy(idi, ido, p.p_filesz, p.p_offset); 20648905Srnordier addr += p.p_filesz; 20748905Srnordier x++; 20848905Srnordier } 20948905Srnordier if (!x) 21048905Srnordier return -1; 21148905Srnordier kh->dload = load; 21248905Srnordier kh->dsize = addr - load; 21348905Srnordier kh->isize = kh->dsize + n; 21448905Srnordier kh->entry = e->e_entry; 21548905Srnordier return 0; 21648905Srnordier} 21748905Srnordier 21848905Srnordier/* 21948905Srnordier * "Load" an a.out-format executable. 22048905Srnordier */ 22148905Srnordierstatic int 22248905Srnordierld_aout(const struct iodesc * idi, const struct iodesc * ido, 223130927Sobrien struct kgz_hdr * kh, const struct exec * a) 22448905Srnordier{ 22548905Srnordier size_t load, addr; 22648905Srnordier 227130927Sobrien load = addr = N_TXTADDR(*a); 228130927Sobrien xcopy(idi, ido, le32toh(a->a_text), N_TXTOFF(*a)); 229130927Sobrien addr += le32toh(a->a_text); 230130927Sobrien if (N_DATADDR(*a) != addr) 23148905Srnordier return -1; 232130927Sobrien xcopy(idi, ido, le32toh(a->a_data), N_DATOFF(*a)); 233130927Sobrien addr += le32toh(a->a_data); 23448905Srnordier kh->dload = load; 23548905Srnordier kh->dsize = addr - load; 236130927Sobrien kh->isize = kh->dsize + le32toh(a->a_bss); 237130927Sobrien kh->entry = le32toh(a->a_entry); 23848905Srnordier return 0; 23948905Srnordier} 240