kgzcmp.c revision 48905
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