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