XEmacs 21.2.28 "Hermes".
[chise/xemacs-chise.git.1] / src / unexenix.c
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 \f
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 \f
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 }