comparison src/unexenix.c @ 0:376386a54a3c r19-14

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