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