1
0
mirror of https://github.com/DoctorWkt/unix-jun72.git synced 2026-02-10 18:30:41 +00:00
Files
DoctorWkt.unix-jun72/tools/apout/v1trap.c
2008-05-06 23:25:22 +00:00

523 lines
15 KiB
C

/* v1trap.c - Deal with 1st Edition trap instructions.
*
* $Revision: 1.15 $
* $Date: 2002/06/10 11:43:24 $
*/
#ifdef EMUV1
#include "defines.h"
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/wait.h>
#include <signal.h>
#include <termios.h>
#include <utime.h>
#include "v1trap.h"
#ifdef __linux__
# undef STREAM_BUFFERING /* It seems to work */
#else
# define STREAM_BUFFERING /* but not for Linux */
#endif
/* Forward prototypes */
#ifdef __STDC__
#define P(s) s
#else
#define P(s) ()
#endif
static int v1trap_exec P((void));
static int v1open_dir P((char *name));
static u_int32_t sectosixty P((time_t tim));
#undef P
/* V1 keeps some of the arguments to syscalls in registers, and some
* after the `sys' instruction itself. The list below gives the number
* of words, and the number in registers.
*/
struct v1sysent {
int nwords;
int nregs;
};
static struct v1sysent v1arg[] = {
{0, 0}, {0, 0}, {0, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 1}, {1, 1},
{2, 0}, {2, 0}, {1, 0}, {2, 0}, {1, 0}, {0, 0}, {2, 0}, {2, 0},
{2, 0}, {1, 0}, {2, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 0}, {1, 1},
{1, 1}, {0, 0}, {1, 0}, {1, 0}, {2, 1}, {1, 0}, {1, 0}, {2, 1},
{2, 1}, {1, 0}
};
/* Seeks on files in /dev are done in 512-byte blocks, not bytes.
* If a fd's entry in the following table is 1, then it's a device
* and not a file.
*/
int8_t isdev[NFILE]= {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static arglist V1A;
void v1trap()
{
extern int32_t AC, MQ; /* in ke11a.c */
int i, mode, pid;
int status, exitval, errval; /* used in V2 wait */
int whence;
u_int16_t argbase;
int trapnum;
long larg;
char *buf, *buf2;
char *fmode; /* used with fdopen only */
struct stat stbuf; /* used in STAT */
struct tr_v1stat *t1; /* used in STAT */
struct timeval tval[2]; /* used in SMTIME */
/* Work out the actual trap number, and */
/* shift the PC up past any arguments */
/* to the syscall. Calculate base of args */
trapnum = ir & 077;
argbase = regs[PC];
regs[PC] += 2 * (v1arg[trapnum].nwords - v1arg[trapnum].nregs);
/* Move arguments into V1A so we can use them */
for (i = 0; i < v1arg[trapnum].nregs; i++) V1A.uarg[i] = regs[i];
for (; i < v1arg[trapnum].nwords; i++, argbase += 2)
ll_word(argbase, V1A.uarg[i]);
TrapDebug((dbg_file, "pid %d %s: ", (int) getpid(), v1trap_name[trapnum]));
switch (trapnum) {
/* XXX STILL TO DO: V1_GTTY, V1_STTY, V1_TELL */
/* These syscalls are ignored, and return */
/* with no effect on the caller */
case V1_BREAK:
case V1_CEMT:
case V1_ILGINS:
case V1_INTR:
case V1_QUIT:
case V1_RELE: return;
/* These syscalls are not implemented, and */
/* always return no error to the caller */
case V1_GTTY:
case V1_STTY: i=0; break;
/* These syscalls are not implemented, and */
/* always return an error to the caller */
case V1_MOUNT:
case V1_UMOUNT: i = -1; break;
case V1_EXIT:
if (Binary==IS_V1) exit(0);
if (Binary==IS_V2) {
exitval=regs[0] & 0xff;
if (regs[PC]==16790) exitval=0; /* s2-tape /bin/as doesn't set r0 */
TrapDebug((dbg_file, " with exitval %d\n", exitval));
exit(exitval);
}
i = -1;
break;
#define EPOCH71 31536000 /* # seconds from 1970 to 1971 */
#define EPOCH72 63072000 /* # seconds from 1970 to 1972 */
case V1_SMDATE:
buf = xlate_filename(&dspace[uarg1]);
if (buf[0] == '\0') buf = "."; /* Not documented anywhere */
if (uarg1 == 0) buf = "."; /* Who knows? for V1 */
i = stat(buf, &stbuf);
TrapDebug((dbg_file, " on %s (stat %d) ", buf, i));
if (i == -1) break;
/* Copy access time to preserve it */
tval[0].tv_sec= stbuf.st_atime; tval[0].tv_usec=0;
larg= (AC << 16) | (MQ & 0xffff); /* Get mod time in 60ths of a second */
TrapDebug((dbg_file, " %ld -> ", larg));
larg= larg/60 + EPOCH72; /* Convert to seconds since 1970 */
TrapDebug((dbg_file, " 0x%lx ", larg));
tval[1].tv_sec= larg; tval[1].tv_usec=0;
i=utimes(buf, tval);
TrapDebug((dbg_file, " and %d for utimes ", i));
break;
case V1_TIME:
/* Kludge: treat start of this year as the epoch. */
/* Find #seconds from yearstart to now, multiply */
/* by 60 so as to be in V1 units */
larg = sectosixty(time(NULL));
MQ = (int) larg & 0xffff;
AC = ((int) larg >> 16) & 0xffff;
i = 0; break;
case V1_SEEK:
/* Work out the args before we do the lseek */
whence = uarg3;
switch (uarg3) {
case 0:
larg = uarg2; break;
case 1:
case 2:
larg = sarg2; break;
}
if (ValidFD(sarg1) && isdev[sarg1]) larg*= 512;
#ifdef STREAM_BUFFERING
if (ValidFD(sarg1) && stream[sarg1]) {
i = fseek(stream[sarg1], larg, whence);
if (i == 0)
i = ftell(stream[sarg1]);
} else
#endif
i = lseek(sarg1, larg, whence);
TrapDebug((dbg_file, " on fd %d amt %ld whence %d return %d ",
sarg1, larg, whence, i));
if (i != -1) i = 0;
regs[0] = i;
break;
case V1_READ:
buf = &dspace[uarg2];
#ifdef STREAM_BUFFERING
if (ValidFD(sarg1) && stream[sarg1])
i = fread(buf, 1, sarg3, stream[sarg1]);
else
#endif
i = read(sarg1, buf, sarg3);
TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
regs[0] = i; break;
case V1_LINK:
buf = xlate_filename(&dspace[uarg1]);
buf2 = xlate_filename(&dspace[uarg2]);
i = link(buf, buf2);
regs[0] = i; break;
case V1_WRITE:
buf = &dspace[uarg2];
#ifdef STREAM_BUFFERING
if (ValidFD(sarg1) && stream[sarg1])
i = fwrite(buf, 1, sarg3, stream[sarg1]);
else
#endif
i = write(sarg1, buf, sarg3);
TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
regs[0] = i; break;
case V1_CLOSE:
#ifdef STREAM_BUFFERING
if (ValidFD(sarg1) && stream[sarg1]) {
i = fclose(stream[sarg1]);
stream[sarg1] = NULL;
} else
#endif
i = close(sarg1);
if ((i==0) && ValidFD(sarg1)) isdev[sarg1]=0;
TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
break;
case V1_STAT:
buf = xlate_filename(&dspace[uarg1]);
if (buf[0] == '\0') buf = "."; /* Not documented anywhere */
if (uarg1 == 0) buf = "."; /* Who knows? for V1 */
buf2 = &dspace[uarg2];
i = stat(buf, &stbuf);
TrapDebug((dbg_file, " on %s return %d ", buf, i));
goto dostat;
case V1_FSTAT:
buf2 = &dspace[uarg2];
i = fstat(sarg1, &stbuf);
TrapDebug((dbg_file, " on fd %d return %d ", sarg1, i));
dostat:
if (i == -1) break;
t1 = (struct tr_v1stat *) buf2;
/* Inode numbers <41 are reserved for */
/* device files. Ensure we don't use them */
t1->inum = stbuf.st_ino & 0x7fff; if (t1->inum<41) t1->inum+=100;
t1->inl = stbuf.st_nlink;
t1->iuid = stbuf.st_uid;
t1->isize = (u_int16_t) (stbuf.st_size & 0xffff);
t1->iflags = (u_int16_t) (V1_ST_USED | V1_ST_MODIFIED);
if (stbuf.st_size > 4095) t1->iflags |= V1_ST_LARGE;
if (stbuf.st_mode & S_IFDIR) t1->iflags |= V1_ST_ISDIR;
if (stbuf.st_mode & S_ISUID) t1->iflags |= V1_ST_SETUID;
if (stbuf.st_mode & S_IXUSR) t1->iflags |= V1_ST_EXEC;
if (stbuf.st_mode & S_IRUSR) t1->iflags |= V1_ST_OWNREAD;
if (stbuf.st_mode & S_IWUSR) t1->iflags |= V1_ST_OWNWRITE;
if (stbuf.st_mode & S_IROTH) t1->iflags |= V1_ST_WRLDREAD;
if (stbuf.st_mode & S_IWOTH) t1->iflags |= V1_ST_WRLDWRITE;
larg = sectosixty(stbuf.st_ctime); copylong(t1->ctime, larg);
larg = sectosixty(stbuf.st_mtime); copylong(t1->mtime, larg);
break;
case V1_UNLINK:
buf = xlate_filename(&dspace[uarg1]);
i = unlink(buf);
break;
case V1_OPEN:
buf = xlate_filename(&dspace[uarg1]);
i = stat(buf, &stbuf); /* If file is a directory */
if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
i = v1open_dir(buf);
fmode = "w+";
TrapDebug((dbg_file, "(dir) on %s return %d ", buf, i));
} else {
switch (sarg2) {
case 0:
sarg2 = O_RDONLY; fmode = "r"; break;
case 1:
sarg2 = O_WRONLY; fmode = "w"; break;
default:
sarg2 = O_RDWR; fmode = "w+"; break;
}
i = open(buf, sarg2);
TrapDebug((dbg_file, " on %s return %d ", buf, i));
}
regs[0] = i;
if (ValidFD(i) && !strncmp(&dspace[uarg1],"/dev/",5)) {
TrapDebug((dbg_file, " (device file) "));
isdev[i]=1;
}
#ifdef STREAM_BUFFERING
if (i==-1) break;
#if 0
/* Now get its stream pointer if possible */
/* Can someone explain why fdopen doesn't work for O_RDWR? */
if (ValidFD(i) && !isatty(i) && (sarg2 != O_RDWR)) {
stream[i] = fdopen(i, fmode); streammode[i] = fmode;
}
#endif
stream[i] = fdopen(i, fmode); streammode[i] = fmode;
#endif
break;
case V1_CHMOD:
buf = xlate_filename(&dspace[uarg1]);
mode = 0;
if (uarg2 & V1_ST_SETUID) mode |= S_ISUID;
if (uarg2 & V1_ST_EXEC) mode |= S_IXUSR | S_IXGRP | S_IXOTH;
if (uarg2 & V1_ST_OWNREAD) mode |= S_IRUSR;
if (uarg2 & V1_ST_OWNWRITE) mode |= S_IWUSR;
if (uarg2 & V1_ST_WRLDREAD) mode |= S_IRGRP | S_IROTH;
if (uarg2 & V1_ST_WRLDWRITE) mode |= S_IWGRP | S_IWOTH;
i = chmod(buf, mode);
break;
case V1_MKDIR:
buf = xlate_filename(&dspace[uarg1]);
mode = 0;
if (uarg2 & V1_ST_SETUID) mode |= S_ISUID;
if (uarg2 & V1_ST_EXEC) mode |= S_IXUSR | S_IXGRP | S_IXOTH;
if (uarg2 & V1_ST_OWNREAD) mode |= S_IRUSR;
if (uarg2 & V1_ST_OWNWRITE) mode |= S_IWUSR;
if (uarg2 & V1_ST_WRLDREAD) mode |= S_IRGRP | S_IROTH;
if (uarg2 & V1_ST_WRLDWRITE) mode |= S_IWGRP | S_IWOTH;
i = mkdir(buf, mode);
break;
case V1_CHOWN:
buf = xlate_filename(&dspace[uarg1]);
uarg2&= 0x3fff; /* Why are uids > 16384? */
i = chown(buf, uarg2, 0);
TrapDebug((dbg_file, " %d on %s return %d",uarg2,buf,i));
break;
case V1_CHDIR:
buf = xlate_filename(&dspace[uarg1]);
i = chdir(buf);
break;
case V1_CREAT:
buf = xlate_filename(&dspace[uarg1]);
mode = 0;
if (uarg2 & V1_ST_SETUID) mode |= S_ISUID;
if (uarg2 & V1_ST_EXEC) mode |= S_IXUSR | S_IXGRP | S_IXOTH;
if (uarg2 & V1_ST_OWNREAD) mode |= S_IRUSR;
if (uarg2 & V1_ST_OWNWRITE) mode |= S_IWUSR;
if (uarg2 & V1_ST_WRLDREAD) mode |= S_IRGRP | S_IROTH;
if (uarg2 & V1_ST_WRLDWRITE) mode |= S_IWGRP | S_IWOTH;
i = creat(buf, mode);
TrapDebug((dbg_file, " on %s return %d ", buf, i));
#ifdef STREAM_BUFFERING
if (ValidFD(i)) {
stream[i] = fdopen(i, "w");
streammode[i] = "w";
}
#endif
regs[0] = i; break;
case V1_EXEC:
i = v1trap_exec();
break;
case V1_WAIT:
i = wait(&status);
if (Binary==IS_V1) break;
/* 2nd Edition wait is different */
regs[0] = i; /* Save pid found in r0 */
if (i==-1) { MQ=0; break; }
exitval=WEXITSTATUS(status);
TrapDebug((dbg_file, "exitval %d ",exitval));
errval=0;
if (WIFSIGNALED(status)) {
switch(WTERMSIG(status)) {
case SIGBUS: errval=1; break;
case SIGTRAP: errval=2; break;
case SIGILL: errval=3; break;
case SIGIOT: errval=4; break;
case SIGEMT: errval=6; break;
case SIGQUIT: errval=8; break;
case SIGINT: errval=9; break;
case SIGKILL: errval=10; break;
}
if (WCOREDUMP(status)) errval+=16;
}
TrapDebug((dbg_file, "errval %d ",errval));
MQ= (exitval & 0xff) | (errval<<16);
TrapDebug((dbg_file, "v2 return pid is %d, MQ is 0x%x ",i,MQ));
break;
case V1_FORK:
pid = getpid();
i = fork();
switch (i) {
/* Error, inform the parent */
case -1: break;
/* Child gets ppid in r0 */
case 0:
i = pid; break;
/* Parent: Skip child `bf', pid into r0 */
default:
regs[PC] += 2;
if (Binary==IS_V2) regs[0]=i;
}
break;
case V1_GETUID:
i = getuid();
break;
regs[0] = i;
case V1_SETUID:
i = setuid(sarg1);
break;
default:
if (trapnum > V1_ILGINS) {
fprintf(stderr, "Apout - unknown syscall %d at PC 0%o\n",
trapnum, regs[PC]);
} else {
fprintf(stderr, "Apout - the %s syscall is not yet implemented\n",
v1trap_name[trapnum]);
}
exit(1);
}
/* Clear C bit if no error, or */
/* set C bit as there was an error */
if (i == -1) {
SET_CC_C(); TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
} else {
CLR_CC_C(); TrapDebug((dbg_file, "return %d\n", i));
}
#ifdef DEBUG
fflush(dbg_file);
#endif
return;
}
static int v1trap_exec(void)
{
u_int16_t cptr, cptr2;
char *buf, *name, *origpath;
origpath = strdup(&dspace[uarg1]);
name = xlate_filename(origpath);
TrapDebug((dbg_file, "%s Execing %s ", progname, name));
cptr = uarg2;
Argc = 0;
while (Argc < MAX_ARGS) {
ll_word(cptr, cptr2);
if (cptr2 == 0)
break;
buf = &dspace[cptr2];
Argv[Argc++] = strdup(buf);
cptr += 2;
TrapDebug((dbg_file, "%s ", buf));
}
Argv[Argc] = NULL;
TrapDebug((dbg_file, "\n"));
if (load_a_out(name, origpath, 0) == -1) {
for (Argc--; Argc >= 0; Argc--)
free(Argv[Argc]);
return (-1);
}
run(); /* Ok, so it's recursive, I dislike setjmp */
return (0);
}
/* 1st Edition reads directories as if they were ordinary files.
* The solution is to read the directory entries, and build a
* real file, which is passed back to the open call.
* Limitation: 32-bit inode numbers are truncated to 16-bit ones.
*/
static int v1open_dir(char *name)
{
DIR *d;
char *tmpname;
int i;
struct dirent *dent;
struct v1_direct {
int16_t d_ino;
int8_t d_name[8];
} v1dent;
d = opendir(name);
if (d == NULL) return (-1);
tmpname = strdup(TMP_PLATE);
i = mkstemp(tmpname);
if (i == -1) {
fprintf(stderr, "Apout - open_dir couldn't open %s\n", tmpname);
exit(1);
}
unlink(tmpname);
free(tmpname);
while ((dent = readdir(d)) != NULL) {
v1dent.d_ino = dent->d_fileno & 0x7fff;
if (v1dent.d_ino<41) v1dent.d_ino+=100;
strncpy(v1dent.d_name, dent->d_name, 8);
write(i, &v1dent, 10);
}
closedir(d);
lseek(i, 0, SEEK_SET);
return (i);
}
/* Given a time, work out the number of 1/60ths of seconds since
* the start of that time's year
*/
u_int32_t sectosixty(time_t tim)
{
time_t epoch;
u_int32_t diff;
struct tm *T;
T = gmtime(&tim);
T->tm_sec = T->tm_min = T->tm_hour = T->tm_mon = 0;
T->tm_mday = 1;
epoch = timegm(T); /* Find time at start of year */
diff = 60 * (tim - epoch);
if (diff > 0x71172C00) {
fprintf(stderr, "Apout - V1 sectosixty too big by %d\n",diff-0x71172C00);
}
return (diff);
}
#endif /* EMUV1 */