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