#include <config.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <varargs.h>
#include <a.out.h>
static void fatal_unexec ();
#define READ(_fd, _buffer, _size, _error_message, _error_arg) \
errno = EEOF; \
if (read(_fd, _buffer, _size) != _size) \
fatal_unexec(_error_message, _error_arg);
#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
if (write(_fd, _buffer, _size) != _size) \
fatal_unexec(_error_message, _error_arg);
#define SEEK(_fd, _position, _error_message, _error_arg) \
errno = EEOF; \
if (lseek(_fd, _position, L_SET) != _position) \
fatal_unexec(_error_message, _error_arg);
extern int errno;
extern char *strerror ();
#define EEOF -1
#ifndef L_SET
#define L_SET 0
#endif
check_exec (x)
struct xexec *x;
{
}
unexec (new_name, a_name, data_start, bss_start, entry_address)
char *new_name, *a_name;
unsigned data_start, bss_start, entry_address;
{
char *sbrk (), *datalim = sbrk (0), *data_org;
long segpos, textseen, textpos, textlen, datapos, datadiff, datalen;
struct xexec u_xexec,
*u_xexecp = &u_xexec;
struct xext u_xext,
*u_xextp = &u_xext;
struct xseg u_xseg,
*u_xsegp = &u_xseg;
int i, nsegs, isdata = 0, infd, outfd;
infd = open (a_name, O_RDONLY, 0);
if (infd < 0) fatal_unexec ("opening %s", a_name);
outfd = creat (new_name, 0666);
if (outfd < 0) fatal_unexec ("creating %s", new_name);
READ (infd, u_xexecp, sizeof (struct xexec),
"error reading %s", a_name);
check_exec (u_xexecp);
READ (infd, u_xextp, sizeof (struct xext),
"error reading %s", a_name);
segpos = u_xextp->xe_segpos;
nsegs = u_xextp->xe_segsize / sizeof (struct xseg);
SEEK (infd, segpos, "seek error on %s", a_name);
for (i = 0; i < nsegs; i ++)
{
READ (infd, u_xsegp, sizeof (struct xseg),
"error reading %s", a_name);
switch (u_xsegp->xs_type)
{
case XS_TTEXT:
{
if (i == 0)
{
textpos = u_xsegp->xs_filpos;
textlen = u_xsegp->xs_psize;
break;
}
fatal_unexec ("invalid text segment in %s", a_name);
}
case XS_TDATA:
{
if (i == 1)
{
datapos = u_xsegp->xs_filpos;
datalen = datalim - (data_org = (char *)(u_xsegp->xs_rbase));
datadiff = datalen - u_xsegp->xs_psize;
break;
}
fatal_unexec ("invalid data segment in %s", a_name);
}
default:
{
if (i > 1) break;
fatal_unexec ("invalid segment record in %s", a_name);
}
}
}
u_xexecp->x_data = datalen;
u_xexecp->x_bss = 0;
WRITE (outfd, u_xexecp, sizeof (struct xexec),
"error writing %s", new_name);
WRITE (outfd, u_xextp, sizeof (struct xext),
"error writing %s", new_name);
SEEK (infd, segpos, "seek error on %s", a_name);
SEEK (outfd, segpos, "seek error on %s", new_name);
copyrec (infd, outfd, sizeof (struct xseg), a_name, new_name);
READ (infd, u_xsegp, sizeof (struct xseg),
"error reading %s", a_name);
u_xsegp->xs_psize = u_xsegp->xs_vsize = datalen;
u_xsegp->xs_attr &= (~XS_AITER & ~XS_ABSS);
WRITE (outfd, u_xsegp, sizeof (struct xseg),
"error writing %s", new_name);
for (i = 2; i < nsegs; i++)
{
READ (infd, u_xsegp, sizeof (struct xseg),
"error reading %s", a_name);
u_xsegp->xs_filpos += datadiff;
WRITE (outfd, u_xsegp, sizeof (struct xseg),
"error writing %s", new_name);
}
SEEK (infd, textpos, "seek error on %s", a_name);
SEEK (outfd, textpos, "seek error on %s", new_name);
copyrec (infd, outfd, textlen, a_name, new_name);
SEEK (outfd, datapos, "seek error on %s", new_name);
WRITE (outfd, data_org, datalen,
"write error on %s", new_name);
for (i = 2, segpos += (2 * sizeof (struct xseg));
i < nsegs;
i++, segpos += sizeof (struct xseg))
{
SEEK (infd, segpos, "seek error on %s", a_name);
READ (infd, u_xsegp, sizeof (struct xseg),
"read error on %s", a_name);
SEEK (infd, u_xsegp->xs_filpos, "seek error on %s", a_name);
SEEK (outfd, u_xsegp->xs_filpos + datadiff, "seek error on %s", new_name);
copyrec (infd, outfd, u_xsegp->xs_psize, a_name, new_name);
}
close (infd);
close (outfd);
mark_x (new_name);
return 0;
}
copyrec (infd, outfd, len, in_name, out_name)
int infd, outfd, len;
char *in_name, *out_name;
{
char buf[BUFSIZ];
int chunk;
while (len)
{
chunk = BUFSIZ;
if (chunk > len)
chunk = len;
READ (infd, buf, chunk, "error reading %s", in_name);
WRITE (outfd, buf, chunk, "error writing %s", out_name);
len -= chunk;
}
}
static
mark_x (name)
char *name;
{
struct stat sbuf;
int um = umask (777);
umask (um);
if (stat (name, &sbuf) < 0)
fatal_unexec ("getting protection on %s", name);
sbuf.st_mode |= 0111 & ~um;
if (chmod (name, sbuf.st_mode) < 0)
fatal_unexec ("setting protection on %s", name);
}
static void
fatal_unexec (s, va_alist)
va_dcl
{
va_list ap;
if (errno == EEOF)
fputs ("unexec: unexpected end of file, ", stderr);
else
fprintf (stderr, "unexec: %s, ", strerror (errno));
va_start (ap);
_doprnt (s, ap, stderr);
fputs (".\n", stderr);
exit (1);
}