0
+ − 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 }