Update years in copyright notice; nfc.
[bpt/emacs.git] / src / unexenix.c
CommitLineData
d427b66a
JB
1/* Unexec for Xenix.
2 Note that the GNU project considers support for Xenix operation
3 a peripheral activity which should not be allowed to divert effort
4 from development of the GNU system. Changes in this code will be
5 installed when Xenix users send them in, but aside from that
6 we don't plan to think about it, or about whether other Emacs
7 maintenance might break it.
8
0b5538bd 9 Copyright (C) 1988, 1994, 2002, 2003, 2004,
aaef169d 10 2005, 2006 Free Software Foundation, Inc.
d427b66a
JB
11
12This file is part of GNU Emacs.
13
14GNU Emacs is free software; you can redistribute it and/or modify
15it under the terms of the GNU General Public License as published by
20c92ac7 16the Free Software Foundation; either version 2, or (at your option)
d427b66a
JB
17any later version.
18
19GNU Emacs is distributed in the hope that it will be useful,
20but WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22GNU General Public License for more details.
23
24You should have received a copy of the GNU General Public License
25along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
26the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27Boston, MA 02110-1301, USA. */
d427b66a
JB
28
29\f
30
31/*
32 On 80386 Xenix, segmentation screws prevent us from modifying the text
33 segment at all. We basically just plug a new value for "data segment
34 size" into the countless headers and copy the other records straight
35 through. The data segment is ORG'ed at the xs_rbase value of the data
36 segment's xseg record (always @ 0x1880000, thanks to the "sophisticated
37 memory management hardware" of the chip) and extends to sbrk(0), exactly.
38 This code is afraid to malloc (should it be?), and alloca has to be the
39 wimpy, malloc-based version; consequently, data is usually copied in
40 smallish chunks.
41
42 gb@entity.com
43*/
44
18160b98 45#include <config.h>
d427b66a
JB
46#include <sys/types.h>
47#include <fcntl.h>
48#include <sys/file.h>
49#include <sys/stat.h>
50#include <stdio.h>
51#include <varargs.h>
52#include <a.out.h>
53
54static void fatal_unexec ();
55
56#define READ(_fd, _buffer, _size, _error_message, _error_arg) \
57 errno = EEOF; \
58 if (read(_fd, _buffer, _size) != _size) \
59 fatal_unexec(_error_message, _error_arg);
60
61#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
62 if (write(_fd, _buffer, _size) != _size) \
63 fatal_unexec(_error_message, _error_arg);
64
65#define SEEK(_fd, _position, _error_message, _error_arg) \
66 errno = EEOF; \
67 if (lseek(_fd, _position, L_SET) != _position) \
68 fatal_unexec(_error_message, _error_arg);
69
70extern int errno;
20c92ac7 71extern char *strerror ();
d427b66a
JB
72#define EEOF -1
73
74#ifndef L_SET
75#define L_SET 0
76#endif
77\f
78/* Should check the magic number of the old executable;
79 not yet written. */
80check_exec (x)
81 struct xexec *x;
82{
83}
84
85
86unexec (new_name, a_name, data_start, bss_start, entry_address)
87 char *new_name, *a_name;
88 unsigned data_start, bss_start, entry_address;
89{
90 char *sbrk (), *datalim = sbrk (0), *data_org;
91 long segpos, textseen, textpos, textlen, datapos, datadiff, datalen;
92
93 struct xexec u_xexec, /* a.out header */
94 *u_xexecp = &u_xexec;
95 struct xext u_xext, /* extended header */
96 *u_xextp = &u_xext;
97 struct xseg u_xseg, /* segment table entry */
98 *u_xsegp = &u_xseg;
99 int i, nsegs, isdata = 0, infd, outfd;
100
101 infd = open (a_name, O_RDONLY, 0);
102 if (infd < 0) fatal_unexec ("opening %s", a_name);
103
104 outfd = creat (new_name, 0666);
105 if (outfd < 0) fatal_unexec ("creating %s", new_name);
106
107 READ (infd, u_xexecp, sizeof (struct xexec),
108 "error reading %s", a_name);
109 check_exec (u_xexecp);
110 READ (infd, u_xextp, sizeof (struct xext),
111 "error reading %s", a_name);
112 segpos = u_xextp->xe_segpos;
113 nsegs = u_xextp->xe_segsize / sizeof (struct xseg);
114 SEEK (infd, segpos, "seek error on %s", a_name);
115 for (i = 0; i < nsegs; i ++)
116 {
117 READ (infd, u_xsegp, sizeof (struct xseg),
118 "error reading %s", a_name);
119 switch (u_xsegp->xs_type)
120 {
121 case XS_TTEXT:
122 {
123 if (i == 0)
124 {
125 textpos = u_xsegp->xs_filpos;
126 textlen = u_xsegp->xs_psize;
127 break;
128 }
129 fatal_unexec ("invalid text segment in %s", a_name);
130 }
131 case XS_TDATA:
132 {
133 if (i == 1)
134 {
135 datapos = u_xsegp->xs_filpos;
136 datalen = datalim - (data_org = (char *)(u_xsegp->xs_rbase));
137 datadiff = datalen - u_xsegp->xs_psize;
138 break;
139 }
140 fatal_unexec ("invalid data segment in %s", a_name);
141 }
142 default:
143 {
144 if (i > 1) break;
145 fatal_unexec ("invalid segment record in %s", a_name);
146 }
147 }
148 }
149 u_xexecp->x_data = datalen;
150 u_xexecp->x_bss = 0;
151 WRITE (outfd, u_xexecp, sizeof (struct xexec),
152 "error writing %s", new_name);
153 WRITE (outfd, u_xextp, sizeof (struct xext),
154 "error writing %s", new_name);
155 SEEK (infd, segpos, "seek error on %s", a_name);
156 SEEK (outfd, segpos, "seek error on %s", new_name);
157
158 /* Copy the text segment record verbatim. */
159
160 copyrec (infd, outfd, sizeof (struct xseg), a_name, new_name);
161
162 /* Read, modify, write the data segment record. */
163
164 READ (infd, u_xsegp, sizeof (struct xseg),
165 "error reading %s", a_name);
166 u_xsegp->xs_psize = u_xsegp->xs_vsize = datalen;
167 u_xsegp->xs_attr &= (~XS_AITER & ~XS_ABSS);
168 WRITE (outfd, u_xsegp, sizeof (struct xseg),
169 "error writing %s", new_name);
170
171 /* Now copy any additional segment records, adjusting their
172 file position field */
173
174 for (i = 2; i < nsegs; i++)
175 {
176 READ (infd, u_xsegp, sizeof (struct xseg),
177 "error reading %s", a_name);
178 u_xsegp->xs_filpos += datadiff;
179 WRITE (outfd, u_xsegp, sizeof (struct xseg),
180 "error writing %s", new_name);
181 }
182
183 SEEK (infd, textpos, "seek error on %s", a_name);
184 SEEK (outfd, textpos, "seek error on %s", new_name);
185 copyrec (infd, outfd, textlen, a_name, new_name);
186
187 SEEK (outfd, datapos, "seek error on %s", new_name);
188 WRITE (outfd, data_org, datalen,
189 "write error on %s", new_name);
190
177c0ea7 191 for (i = 2, segpos += (2 * sizeof (struct xseg));
d427b66a
JB
192 i < nsegs;
193 i++, segpos += sizeof (struct xseg))
194 {
195 SEEK (infd, segpos, "seek error on %s", a_name);
196 READ (infd, u_xsegp, sizeof (struct xseg),
197 "read error on %s", a_name);
198 SEEK (infd, u_xsegp->xs_filpos, "seek error on %s", a_name);
199 /* We should be at eof in the output file here, but we must seek
200 because the xs_filpos and xs_psize fields in symbol table
201 segments are inconsistent. */
202 SEEK (outfd, u_xsegp->xs_filpos + datadiff, "seek error on %s", new_name);
203 copyrec (infd, outfd, u_xsegp->xs_psize, a_name, new_name);
204 }
205 close (infd);
206 close (outfd);
207 mark_x (new_name);
208 return 0;
209}
210
211copyrec (infd, outfd, len, in_name, out_name)
212 int infd, outfd, len;
213 char *in_name, *out_name;
214{
215 char buf[BUFSIZ];
216 int chunk;
217
218 while (len)
219 {
220 chunk = BUFSIZ;
221 if (chunk > len)
222 chunk = len;
223 READ (infd, buf, chunk, "error reading %s", in_name);
224 WRITE (outfd, buf, chunk, "error writing %s", out_name);
225 len -= chunk;
226 }
227}
228
229/*
230 * mark_x
231 *
eb8c3be9 232 * After successfully building the new a.out, mark it executable
d427b66a
JB
233 */
234static
235mark_x (name)
236 char *name;
237{
238 struct stat sbuf;
239 int um = umask (777);
240 umask (um);
241 if (stat (name, &sbuf) < 0)
242 fatal_unexec ("getting protection on %s", name);
243 sbuf.st_mode |= 0111 & ~um;
244 if (chmod (name, sbuf.st_mode) < 0)
245 fatal_unexec ("setting protection on %s", name);
246}
247
248static void
249fatal_unexec (s, va_alist)
250 va_dcl
251{
252 va_list ap;
253 if (errno == EEOF)
254 fputs ("unexec: unexpected end of file, ", stderr);
d427b66a 255 else
20c92ac7 256 fprintf (stderr, "unexec: %s, ", strerror (errno));
d427b66a
JB
257 va_start (ap);
258 _doprnt (s, ap, stderr);
259 fputs (".\n", stderr);
260 exit (1);
261}
ab5796a9
MB
262
263/* arch-tag: ce26be27-370a-438d-83b4-766059749a02
264 (do not change this comment) */