xref: /freebsd-11-stable/usr.sbin/kgzip/kgzcmp.c (revision 25d4b2c1b89d42d752e23f9935692f481cb272ea)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1999 Global Technology Associates, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #define	_KERNEL
32 #include <sys/param.h>
33 #undef _KERNEL
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37 
38 #include <err.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 
44 #include <a.out.h>
45 
46 #include "aouthdr.h"
47 #include "elfhdr.h"
48 #include "kgzip.h"
49 
50 static void mk_data(const struct iodesc *i, const struct iodesc *,
51 		    struct kgz_hdr *, size_t);
52 static int ld_elf(const struct iodesc *, const struct iodesc *,
53 		  struct kgz_hdr *, const Elf32_Ehdr *);
54 static 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  */
60 void
kgzcmp(struct kgz_hdr * kh,const char * f1,const char * f2)61 kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2)
62 {
63     struct iodesc idi, ido;
64     struct kgz_hdr khle;
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     mk_data(&idi, &ido, kh,
76 	    (format == F_AOUT ? sizeof(struct kgz_aouthdr0) :
77 				sizeof(struct kgz_elfhdr)) +
78 	     sizeof(struct kgz_hdr));
79     kh->dload &= 0xffffff;
80     kh->entry &= 0xffffff;
81     if (format == F_AOUT) {
82 	struct kgz_aouthdr0 ahdr0 = aouthdr0;
83 	struct kgz_aouthdr1 ahdr1 = aouthdr1;
84 	unsigned x = (sizeof(struct kgz_hdr) + kh->nsize) & (16 - 1);
85 	if (x) {
86 	    x = 16 - x;
87 	    xzero(&ido, x);
88 	}
89 	xwrite(&ido, &ahdr1, sizeof(ahdr1));
90 	ahdr0.a.a_data += kh->nsize + x;
91 	xseek(&ido, 0);
92 	xwrite(&ido, &ahdr0, sizeof(ahdr0));
93     } else {
94 	struct kgz_elfhdr ehdr = elfhdr;
95 	ehdr.st[KGZ_ST_KGZ_NDATA].st_size = htole32(kh->nsize);
96 	ehdr.sh[KGZ_SH_DATA].sh_size =
97 	    htole32(le32toh(ehdr.sh[KGZ_SH_DATA].sh_size) + kh->nsize);
98 	xseek(&ido, 0);
99 	xwrite(&ido, &ehdr, sizeof(ehdr));
100     }
101     khle = *kh;
102     khle.dload = htole32(khle.dload);
103     khle.dsize = htole32(khle.dsize);
104     khle.isize = htole32(khle.isize);
105     khle.entry = htole32(khle.entry);
106     khle.nsize = htole32(khle.nsize);
107     xwrite(&ido, &khle, sizeof(khle));
108     xclose(&ido);
109     xclose(&idi);
110 }
111 
112 /*
113  * Make encoded (compressed) data.
114  */
115 static void
mk_data(const struct iodesc * idi,const struct iodesc * ido,struct kgz_hdr * kh,size_t off)116 mk_data(const struct iodesc * idi, const struct iodesc * ido,
117 	struct kgz_hdr * kh, size_t off)
118 {
119     union {
120 	struct exec ex;
121 	Elf32_Ehdr ee;
122     } hdr;
123     struct stat sb;
124     struct iodesc idp;
125     int fd[2];
126     pid_t pid;
127     size_t n;
128     int fmt, status, e;
129 
130     n = xread(idi, &hdr, sizeof(hdr), 0);
131     fmt = 0;
132     if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee))
133 	fmt = F_ELF;
134     else if (n >= sizeof(hdr.ex) && N_GETMAGIC(hdr.ex) == ZMAGIC)
135 	fmt = F_AOUT;
136     if (!fmt)
137 	errx(1, "%s: Format not supported", idi->fname);
138     xseek(ido, off);
139     if (pipe(fd))
140 	err(1, NULL);
141     switch (pid = fork()) {
142     case -1:
143 	err(1, NULL);
144     case 0:
145 	close(fd[1]);
146 	dup2(fd[0], STDIN_FILENO);
147 	close(fd[0]);
148 	close(idi->fd);
149 	dup2(ido->fd, STDOUT_FILENO);
150 	close(ido->fd);
151 	execlp("gzip", "gzip", "-9n", (char *)NULL);
152 	warn(NULL);
153 	_exit(1);
154     default:
155 	close(fd[0]);
156 	idp.fname = "(pipe)";
157 	idp.fd = fd[1];
158 	e = fmt == F_ELF  ? ld_elf(idi, &idp, kh, &hdr.ee) :
159 	    fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1;
160 	close(fd[1]);
161 	if ((pid = waitpid(pid, &status, 0)) == -1)
162 	    err(1, NULL);
163 	if (WIFSIGNALED(status) || WEXITSTATUS(status))
164 	    exit(1);
165     }
166     if (e)
167 	errx(1, "%s: Invalid format", idi->fname);
168     if (fstat(ido->fd, &sb))
169 	err(1, "%s", ido->fname);
170     kh->nsize = sb.st_size - off;
171 }
172 
173 /*
174  * "Load" an ELF-format executable.
175  */
176 static int
ld_elf(const struct iodesc * idi,const struct iodesc * ido,struct kgz_hdr * kh,const Elf32_Ehdr * e)177 ld_elf(const struct iodesc * idi, const struct iodesc * ido,
178        struct kgz_hdr * kh, const Elf32_Ehdr * e)
179 {
180     Elf32_Phdr p;
181     size_t load, addr, n;
182     unsigned x, i;
183 
184     load = addr = n = 0;
185     for (x = i = 0; i < e->e_phnum; i++) {
186 	if (xread(idi, &p, sizeof(p),
187 		  e->e_phoff + i * e->e_phentsize) != e->e_phentsize)
188 	    return -1;
189 	if (p.p_type != PT_LOAD)
190 	    continue;
191 	if (!x)
192 	    load = addr = p.p_vaddr;
193 	else {
194 	    if (p.p_vaddr < addr)
195 		return -1;
196 	    n = p.p_vaddr - addr;
197 	    if (n) {
198 		xzero(ido, n);
199 		addr += n;
200 	    }
201 	}
202 	if (p.p_memsz < p.p_filesz)
203 	    return -1;
204 	n = p.p_memsz - p.p_filesz;
205 	xcopy(idi, ido, p.p_filesz, p.p_offset);
206 	addr += p.p_filesz;
207 	x++;
208     }
209     if (!x)
210 	return -1;
211     kh->dload = load;
212     kh->dsize = addr - load;
213     kh->isize = kh->dsize + n;
214     kh->entry = e->e_entry;
215     return 0;
216 }
217 
218 /*
219  * "Load" an a.out-format executable.
220  */
221 static int
ld_aout(const struct iodesc * idi,const struct iodesc * ido,struct kgz_hdr * kh,const struct exec * a)222 ld_aout(const struct iodesc * idi, const struct iodesc * ido,
223 	struct kgz_hdr * kh, const struct exec * a)
224 {
225     size_t load, addr;
226 
227     load = addr = N_TXTADDR(*a);
228     xcopy(idi, ido, le32toh(a->a_text), N_TXTOFF(*a));
229     addr += le32toh(a->a_text);
230     if (N_DATADDR(*a) != addr)
231 	return -1;
232     xcopy(idi, ido, le32toh(a->a_data), N_DATOFF(*a));
233     addr += le32toh(a->a_data);
234     kh->dload = load;
235     kh->dsize = addr - load;
236     kh->isize = kh->dsize + le32toh(a->a_bss);
237     kh->entry = le32toh(a->a_entry);
238     return 0;
239 }
240