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