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