OpenBSD-4.6/usr.sbin/mopd/common/file.c
/* $OpenBSD: file.c,v 1.12 2006/05/11 05:18:38 maja Exp $ */
/*
* Copyright (c) 1995-96 Mats O Jansson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static const char rcsid[] =
"$OpenBSD: file.c,v 1.12 2006/05/11 05:18:38 maja Exp $";
#endif
#include "os.h"
#include "common/common.h"
#include "common/mopdef.h"
#define INFO_PRINT 1
#ifndef NOAOUT
#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/exec_aout.h>
#endif
#if defined(__bsdi__)
#define NOAOUT
#endif
#if defined(__FreeBSD__)
#include <sys/imgact_aout.h>
#endif
#if !defined(MID_I386)
#define MID_I386 134
#endif
#if !defined(MID_SPARC)
#define MID_SPARC 138
#endif
#if !defined(MID_VAX)
#define MID_VAX 140
#endif
#endif
void
mopFilePutLX(u_char *buf, int idx, u_long value, int cnt)
{
int i;
for (i = 0; i < cnt; i++) {
buf[idx+i] = (u_char)(value % 256);
value = (u_char)(value / 256);
}
}
void
mopFilePutBX(u_char *buf, int idx, u_long value, int cnt)
{
int i;
for (i = 0; i < cnt; i++) {
buf[idx+cnt-1-i] = (u_char)(value % 256);
value = value / 256;
}
}
u_long
mopFileGetLX(void *buffer, int idx, int cnt)
{
u_long ret = 0;
int i;
u_char *buf = (u_char *)buffer;
for (i = 0; i < cnt; i++)
ret = ret*256 + buf[idx+cnt-1-i];
return (ret);
}
u_long
mopFileGetBX(void *buffer, int idx, int cnt)
{
u_long ret = 0;
int i;
u_char *buf = (u_char *)buffer;
for (i = 0; i < cnt; i++)
ret = ret*256 + buf[idx+i];
return (ret);
}
void
mopFileSwapX(void *buffer, int idx, int cnt)
{
int i;
u_char c;
u_char *buf = (u_char *)buffer;
for (i = 0; i < (cnt / 2); i++) {
c = buf[idx+i];
buf[idx+i] = buf[idx+cnt-1-i];
buf[idx+cnt-1-i] = c;
}
}
int
CheckMopFile(int fd)
{
u_char header[512];
short image_type;
if (read(fd, header, 512) != 512)
return (-1);
lseek(fd, 0, SEEK_SET);
image_type = (short)mopFileGetLX(header,IHD_W_ALIAS,2);
switch (image_type) {
case IHD_C_NATIVE: /* Native mode image (VAX) */
case IHD_C_RSX: /* RSX image produced by TKB */
case IHD_C_BPA: /* BASIC plus analog */
case IHD_C_ALIAS: /* Alias */
case IHD_C_CLI: /* Image is CLI */
case IHD_C_PMAX: /* PMAX system image */
case IHD_C_ALPHA: /* ALPHA system image */
break;
default:
return (-1);
}
return (0);
}
int
GetMopFileInfo(int fd, u_long *load, u_long *xfr, int info)
{
u_char header[512];
short image_type, isd, iha;
u_long load_addr, xfr_addr, isize, hbcnt;
if (read(fd, header, 512) != 512)
return (-1);
image_type = (short)mopFileGetLX(header,IHD_W_ALIAS,2);
switch (image_type) {
case IHD_C_NATIVE: /* Native mode image (VAX) */
isd = (short)mopFileGetLX(header,IHD_W_SIZE,2);
iha = (short)mopFileGetLX(header,IHD_W_ACTIVOFF,2);
hbcnt = header[IHD_B_HDRBLKCNT];
isize = mopFileGetLX(header,isd+ISD_W_PAGCNT,2) * 512;
load_addr = (mopFileGetLX(header,isd+ISD_V_VPN,2) &
ISD_M_VPN) * 512;
xfr_addr = mopFileGetLX(header,iha+IHA_L_TFRADR1,4) &
0x7fffffff;
if (info == INFO_PRINT) {
printf("Native Image (VAX)\n");
printf("Header Block Count: %lu\n", hbcnt);
printf("Image Size: %08lx\n", isize);
printf("Load Address: %08lx\n", load_addr);
printf("Transfer Address: %08lx\n", xfr_addr);
}
break;
case IHD_C_RSX: /* RSX image produced by TKB */
hbcnt = mopFileGetLX(header,L_BBLK,2);
isize = mopFileGetLX(header,L_BLDZ,2) * 64;
load_addr = mopFileGetLX(header,L_BSA,2);
xfr_addr = mopFileGetLX(header,L_BXFR,2);
if (info == INFO_PRINT) {
printf("RSX Image\n");
printf("Header Block Count: %lu\n",hbcnt);
printf("Image Size: %08lx\n", isize);
printf("Load Address: %08lx\n", load_addr);
printf("Transfer Address: %08lx\n", xfr_addr);
}
break;
case IHD_C_BPA: /* BASIC plus analog */
if (info == INFO_PRINT) {
printf("BASIC-Plus Image, not supported\n");
}
return (-1);
case IHD_C_ALIAS: /* Alias */
if (info == INFO_PRINT) {
printf("Alias, not supported\n");
}
return (-1);
case IHD_C_CLI: /* Image is CLI */
if (info == INFO_PRINT) {
printf("CLI, not supported\n");
}
return (-1);
case IHD_C_PMAX: /* PMAX system image */
isd = (short)mopFileGetLX(header,IHD_W_SIZE,2);
iha = (short)mopFileGetLX(header,IHD_W_ACTIVOFF,2);
hbcnt = header[IHD_B_HDRBLKCNT];
isize = mopFileGetLX(header,isd+ISD_W_PAGCNT,2) * 512;
load_addr = mopFileGetLX(header,isd+ISD_V_VPN,2) * 512;
xfr_addr = mopFileGetLX(header,iha+IHA_L_TFRADR1,4);
if (info == INFO_PRINT) {
printf("PMAX Image \n");
printf("Header Block Count: %lu\n", hbcnt);
printf("Image Size: %08lx\n", isize);
printf("Load Address: %08lx\n", load_addr);
printf("Transfer Address: %08lx\n", xfr_addr);
}
break;
case IHD_C_ALPHA: /* ALPHA system image */
isd = (short)mopFileGetLX(header,EIHD_L_ISDOFF,4);
hbcnt = mopFileGetLX(header,EIHD_L_HDRBLKCNT,4);
isize = mopFileGetLX(header,isd+EISD_L_SECSIZE,4);
load_addr = 0;
xfr_addr = 0;
if (info == INFO_PRINT) {
printf("Alpha Image \n");
printf("Header Block Count: %lu\n", hbcnt);
printf("Image Size: %08lx\n", isize);
printf("Load Address: %08lx\n", load_addr);
printf("Transfer Address: %08lx\n", xfr_addr);
}
break;
default:
if (info == INFO_PRINT) {
printf("Unknown Image (%d)\n", image_type);
}
return (-1);
}
if (load != NULL)
*load = load_addr;
if (xfr != NULL)
*xfr = xfr_addr;
return (0);
}
#ifndef NOAOUT
int
getMID(int old_mid, int new_mid)
{
int mid;
mid = old_mid;
switch (new_mid) {
case MID_I386:
mid = MID_I386;
break;
#ifdef MID_M68K
case MID_M68K:
mid = MID_M68K;
break;
#endif
#ifdef MID_M68K4K
case MID_M68K4K:
mid = MID_M68K4K;
break;
#endif
#ifdef MID_NS32532
case MID_NS32532:
mid = MID_NS32532;
break;
#endif
case MID_SPARC:
mid = MID_SPARC;
break;
#ifdef MID_PMAX
case MID_PMAX:
mid = MID_PMAX;
break;
#endif
#ifdef MID_VAX
case MID_VAX:
mid = MID_VAX;
break;
#endif
#ifdef MID_ALPHA
case MID_ALPHA:
mid = MID_ALPHA;
break;
#endif
#ifdef MID_MIPS
case MID_MIPS:
mid = MID_MIPS;
break;
#endif
#ifdef MID_ARM6
case MID_ARM6:
mid = MID_ARM6;
break;
#endif
default:
break;
}
return (mid);
}
u_int
getCLBYTES(int mid)
{
u_int clbytes;
switch (mid) {
#ifdef MID_VAX
case MID_VAX:
clbytes = 1024;
break;
#endif
case MID_I386:
#ifdef MID_M68K4K
case MID_M68K4K:
#endif
#ifdef MID_NS32532
case MID_NS32532:
#endif
case MID_SPARC: /* It might be 8192 */
#ifdef MID_PMAX
case MID_PMAX:
#endif
#ifdef MID_MIPS
case MID_MIPS:
#endif
#ifdef MID_ARM6
case MID_ARM6:
#endif
clbytes = 4096;
break;
#ifdef MID_M68K
case MID_M68K:
#endif
#ifdef MID_ALPHA
case MID_ALPHA:
#endif
#if defined(MID_M68K) || defined(MID_ALPHA)
clbytes = 8192;
break;
#endif
default:
clbytes = 0;
}
return (clbytes);
}
#endif
int
CheckAOutFile(int fd)
{
#ifdef NOAOUT
return (-1);
#else
struct exec ex, ex_swap;
int mid = -1;
if (read(fd, &ex, sizeof(ex)) != (ssize_t)sizeof(ex))
return (-1);
lseek(fd, 0, SEEK_SET);
if (read(fd, &ex_swap, sizeof(ex_swap)) != (ssize_t)sizeof(ex_swap))
return (-1);
lseek(fd, 0, SEEK_SET);
mid = getMID(mid, (int)N_GETMID(ex));
if (mid == -1)
mid = getMID(mid, (int)N_GETMID(ex_swap));
if (mid != -1)
return (0);
else
return (-1);
#endif /* NOAOUT */
}
int
GetAOutFileInfo(int fd, u_long *load, u_long *xfr, u_long *a_text,
u_long *a_text_fill, u_long *a_data, u_long *a_data_fill, u_long *a_bss,
u_long *a_bss_fill, int *aout, int info)
{
#ifdef NOAOUT
return (-1);
#else
struct exec ex, ex_swap;
int mid = -1;
u_long magic, clbytes, clofset;
if (read(fd, &ex, sizeof(ex)) != (ssize_t)sizeof(ex))
return (-1);
lseek(fd, 0, SEEK_SET);
if (read(fd, &ex_swap, sizeof(ex_swap)) != (ssize_t)sizeof(ex_swap))
return (-1);
mopFileSwapX(&ex_swap, 0, 4);
mid = getMID(mid, (int)N_GETMID(ex));
if (mid == -1) {
mid = getMID(mid, (int)N_GETMID(ex_swap));
if (mid != -1)
mopFileSwapX(&ex, 0, 4);
}
if (mid == -1)
return (-1);
if (N_BADMAG(ex))
return (-1);
switch (mid) {
case MID_I386:
#ifdef MID_NS32532
case MID_NS32532:
#endif
#ifdef MID_PMAX
case MID_PMAX:
#endif
#ifdef MID_VAX
case MID_VAX:
#endif
#ifdef MID_ALPHA
case MID_ALPHA:
#endif
#ifdef MID_ARM6
case MID_ARM6:
#endif
ex.a_text = (u_int)mopFileGetLX(&ex_swap, 4, 4);
ex.a_data = (u_int)mopFileGetLX(&ex_swap, 8, 4);
ex.a_bss = (u_int)mopFileGetLX(&ex_swap, 12, 4);
ex.a_syms = (u_int)mopFileGetLX(&ex_swap, 16, 4);
ex.a_entry = (u_int)mopFileGetLX(&ex_swap, 20, 4);
ex.a_trsize = (u_int)mopFileGetLX(&ex_swap, 24, 4);
ex.a_drsize = (u_int)mopFileGetLX(&ex_swap, 28, 4);
break;
#ifdef MID_M68K
case MID_M68K:
#endif
#ifdef MID_M68K4K
case MID_M68K4K:
#endif
case MID_SPARC:
#ifdef MID_MIPS
case MID_MIPS:
#endif
ex.a_text = (u_int)mopFileGetBX(&ex_swap, 4, 4);
ex.a_data = (u_int)mopFileGetBX(&ex_swap, 8, 4);
ex.a_bss = (u_int)mopFileGetBX(&ex_swap, 12, 4);
ex.a_syms = (u_int)mopFileGetBX(&ex_swap, 16, 4);
ex.a_entry = (u_int)mopFileGetBX(&ex_swap, 20, 4);
ex.a_trsize = (u_int)mopFileGetBX(&ex_swap, 24, 4);
ex.a_drsize = (u_int)mopFileGetBX(&ex_swap, 28, 4);
break;
default:
break;
}
if (info == INFO_PRINT) {
printf("a.out image (");
switch (N_GETMID(ex)) {
case MID_I386:
printf("i386");
break;
#ifdef MID_M68K
case MID_M68K:
printf("m68k");
break;
#endif
#ifdef MID_M68K4K
case MID_M68K4K:
printf("m68k 4k");
break;
#endif
#ifdef MID_NS32532
case MID_NS32532:
printf("pc532");
break;
#endif
case MID_SPARC:
printf("sparc");
break;
#ifdef MID_PMAX
case MID_PMAX:
printf("pmax");
break;
#endif
#ifdef MID_VAX
case MID_VAX:
printf("vax");
break;
#endif
#ifdef MID_ALPHA
case MID_ALPHA:
printf("alpha");
break;
#endif
#ifdef MID_MIPS
case MID_MIPS:
printf("mips");
break;
#endif
#ifdef MID_ARM6
case MID_ARM6:
printf("arm32");
break;
#endif
default:
break;
}
printf(") Magic: ");
switch (N_GETMAGIC (ex)) {
case OMAGIC:
printf("OMAGIC");
break;
case NMAGIC:
printf("NMAGIC");
break;
case ZMAGIC:
printf("ZMAGIC");
break;
case QMAGIC:
printf("QMAGIC");
break;
default:
printf("Unknown %d",N_GETMAGIC (ex));
}
printf("\n");
printf("Size of text: %08x\n", ex.a_text);
printf("Size of data: %08x\n", ex.a_data);
printf("Size of bss: %08x\n", ex.a_bss);
printf("Size of symbol tab: %08x\n", ex.a_syms);
printf("Transfer Address: %08x\n", ex.a_entry);
printf("Size of reloc text: %08x\n", ex.a_trsize);
printf("Size of reloc data: %08x\n", ex.a_drsize);
}
magic = N_GETMAGIC(ex);
clbytes = getCLBYTES(mid);
clofset = clbytes - 1;
if (load != NULL)
*load = 0;
if (xfr != NULL)
*xfr = ex.a_entry;
if (a_text != NULL)
*a_text = ex.a_text;
if (a_text_fill != NULL) {
if (magic == ZMAGIC || magic == NMAGIC) {
*a_text_fill = clbytes - (ex.a_text & clofset);
if (*a_text_fill == clbytes)
*a_text_fill = 0;
} else
*a_text_fill = 0;
}
if (a_data != NULL)
*a_data = ex.a_data;
if (a_data_fill != NULL) {
if (magic == ZMAGIC || magic == NMAGIC) {
*a_data_fill = clbytes - (ex.a_data & clofset);
if (*a_data_fill == clbytes)
*a_data_fill = 0;
} else
*a_data_fill = 0;
}
if (a_bss != NULL)
*a_bss = ex.a_bss;
if (a_bss_fill != NULL) {
if (magic == ZMAGIC || magic == NMAGIC) {
*a_bss_fill = clbytes - (ex.a_bss & clofset);
if (*a_bss_fill == clbytes)
*a_bss_fill = 0;
} else {
*a_bss_fill = clbytes -
((ex.a_text + ex.a_data + ex.a_bss) & clofset);
if (*a_text_fill == clbytes)
*a_text_fill = 0;
}
}
if (aout != NULL)
*aout = mid;
return (0);
#endif /* NOAOUT */
}
int
GetFileInfo(int fd, u_long *load, u_long *xfr, int *aout, u_long *a_text,
u_long *a_text_fill, u_long *a_data, u_long *a_data_fill, u_long *a_bss,
u_long *a_bss_fill, int info)
{
int err;
err = CheckAOutFile(fd);
if (err == 0) {
err = GetAOutFileInfo(fd, load, xfr, a_text, a_text_fill,
a_data, a_data_fill, a_bss, a_bss_fill, aout, info);
if (err != 0)
return (-1);
} else {
err = CheckMopFile(fd);
if (err == 0) {
err = GetMopFileInfo(fd, load, xfr, info);
if (err != 0)
return (-1);
*aout = -1;
} else
return (-1);
}
return (0);
}
ssize_t
mopFileRead(struct dllist *dlslot, u_char *buf)
{
ssize_t len, outlen;
u_long bsz, total, notdone;
off_t pos;
if (dlslot->aout == -1)
len = read(dlslot->ldfd,buf,dlslot->dl_bsz);
else {
bsz = dlslot->dl_bsz;
pos = dlslot->a_lseek;
len = 0;
total = dlslot->a_text;
if (pos < (off_t)total) {
notdone = total - (u_long)pos;
if (notdone <= bsz)
outlen = read(dlslot->ldfd,&buf[len],notdone);
else
outlen = read(dlslot->ldfd,&buf[len],bsz);
len = len + outlen;
pos = pos + outlen;
bsz = bsz - (u_long)outlen;
}
total = total + dlslot->a_text_fill;
if ((bsz > 0) && (pos < (off_t)total)) {
notdone = total - (u_long)pos;
if (notdone <= bsz)
outlen = (ssize_t)notdone;
else
outlen = (ssize_t)bsz;
bzero(&buf[len],(u_long)outlen);
len = len + outlen;
pos = pos + outlen;
bsz = bsz - (u_long)outlen;
}
total = total + dlslot->a_data;
if ((bsz > 0) && (pos < (off_t)total)) {
notdone = total - (u_long)pos;
if (notdone <= bsz)
outlen = read(dlslot->ldfd,&buf[len],notdone);
else
outlen = read(dlslot->ldfd,&buf[len],bsz);
len = len + outlen;
pos = pos + outlen;
bsz = bsz - (u_long)outlen;
}
total = total + dlslot->a_data_fill;
if ((bsz > 0) && (pos < (off_t)total)) {
notdone = total - (u_long)pos;
if (notdone <= bsz)
outlen = (ssize_t)notdone;
else
outlen = (ssize_t)bsz;
bzero(&buf[len],(u_long)outlen);
len = len + outlen;
pos = pos + outlen;
bsz = bsz - (u_long)outlen;
}
total = total + dlslot->a_bss;
if ((bsz > 0) && (pos < (off_t)total)) {
notdone = total - (u_long)pos;
if (notdone <= bsz)
outlen = (ssize_t)notdone;
else
outlen = (ssize_t)bsz;
bzero(&buf[len],(u_long)outlen);
len = len + outlen;
pos = pos + outlen;
bsz = bsz - (u_long)outlen;
}
total = total + dlslot->a_bss_fill;
if ((bsz > 0) && (pos < (off_t)total)) {
notdone = total - (u_long)pos;
if (notdone <= bsz)
outlen = (ssize_t)notdone;
else
outlen = (ssize_t)bsz;
bzero(&buf[len],(u_long)outlen);
len = len + outlen;
pos = pos + outlen;
bsz = bsz - (u_long)outlen;
}
dlslot->a_lseek = pos;
}
return (len);
}