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
9   Copyright (C) 1988, 1994, 2001, 2002, 2003, 2004,
10                 2005, 2006, 2007  Free Software Foundation, Inc.
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
16the Free Software Foundation; either version 2, or (at your option)
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
26the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27Boston, MA 02110-1301, USA.  */
28
29
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
45#include <config.h>
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;
71extern char *strerror ();
72#define EEOF -1
73
74#ifndef L_SET
75#define L_SET 0
76#endif
77
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
191  for (i = 2, segpos += (2 * sizeof (struct xseg));
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 *
232 * After successfully building the new a.out, mark it executable
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);
255  else
256    fprintf (stderr, "unexec: %s, ", strerror (errno));
257  va_start (ap);
258  _doprnt (s, ap, stderr);
259  fputs (".\n", stderr);
260  exit (1);
261}
262
263/* arch-tag: ce26be27-370a-438d-83b4-766059749a02
264   (do not change this comment) */
265