mirror of
https://github.com/DoctorWkt/unix-jun72.git
synced 2026-02-01 14:32:40 +00:00
710 lines
18 KiB
C
710 lines
18 KiB
C
/* v7trap.c - Deal with V7 trap instructions. V5 and V6 syscalls are also
|
|
* done here, because the syscall interface is nearly the same as V7.
|
|
*
|
|
* $Revision: 1.47 $
|
|
* $Date: 2002/06/10 11:43:24 $
|
|
*/
|
|
#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 "v7trap.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 trap_exec P((int want_env));
|
|
static int open_dir P((char *name));
|
|
static int trap_gtty P((u_int16_t fd, u_int16_t ucnt));
|
|
static int trap_stty P((u_int16_t fd, u_int16_t ucnt));
|
|
static int v7signal P((int sig, int val));
|
|
static void fixv6time P((time_t *t));
|
|
#undef P
|
|
|
|
|
|
/* V7 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 v7sysent {
|
|
int nwords;
|
|
int nregs;
|
|
};
|
|
static struct v7sysent v7arg[] = {
|
|
{0, 0}, {1, 1}, {0, 0}, {3, 1}, {3, 1}, {2, 0}, {1, 1}, {0, 0},
|
|
{2, 0}, {2, 0}, {1, 0}, {2, 0}, {1, 0}, {0, 0}, {3, 0}, {2, 0},
|
|
{3, 0}, {1, 0}, {2, 0}, {4, 1}, {0, 0}, {3, 0}, {1, 0}, {1, 1},
|
|
{0, 0}, {2, 2}, {4, 1}, {1, 1}, {2, 1}, {0, 0}, {2, 0}, {2, 1},
|
|
{2, 1}, {2, 0}, {1, 1}, {1, 0}, {0, 0}, {2, 1}, {0, 0}, {0, 0},
|
|
{1, 1}, {2, 2}, {0, 0}, {1, 0}, {4, 0}, {0, 0}, {1, 1}, {0, 0},
|
|
{2, 0}, {0, 0}, {0, 0}, {1, 0}, {3, 0}, {1, 0}, {3, 0}, {0, 0},
|
|
{4, 0}, {0, 0}, {0, 0}, {3, 0}, {1, 0}, {1, 0}, {0, 0}, {0, 0}
|
|
};
|
|
|
|
static arglist V7A;
|
|
|
|
|
|
void
|
|
v7trap()
|
|
{
|
|
int i, pid, pfd[2];
|
|
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_v7stat *t; /* used in STAT */
|
|
struct tr_v6stat *t6; /* used in STAT */
|
|
struct tr_timeb *tb; /* used in FTIME */
|
|
struct timezone tz; /* used in FTIME */
|
|
struct timeval tv; /* used in FTIME */
|
|
struct timeval utv[2]; /* used in UTIME */
|
|
|
|
|
|
|
|
/* Work out the actual trap number, and */
|
|
/* shift the PC up past any arguments */
|
|
/* to the syscall. Calculate base of args */
|
|
trapnum= ir & 077;
|
|
if (trapnum==S_INDIR) {
|
|
lli_word(regs[PC], argbase);
|
|
ll_word(argbase, ir);
|
|
trapnum= ir & 077; argbase+=2; regs[PC]+=2;
|
|
} else {
|
|
argbase=regs[PC];
|
|
regs[PC]+= 2* (v7arg[trapnum].nwords - v7arg[trapnum].nregs);
|
|
|
|
/* However, V6 seek() has 1 less arg */
|
|
if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
|
|
if (trapnum==S_LSEEK) regs[PC]-=2;
|
|
}
|
|
}
|
|
|
|
/* Move arguments into V7A so we can use them */
|
|
for (i=0; i<v7arg[trapnum].nregs; i++) V7A.uarg[i]= regs[i];
|
|
for (;i<v7arg[trapnum].nwords; i++,argbase+=2)
|
|
ll_word(argbase, V7A.uarg[i]);
|
|
|
|
TrapDebug((dbg_file, "pid %d %s: ", (int)getpid(),v7trap_name[trapnum]));
|
|
|
|
switch (trapnum) {
|
|
/* These syscalls are not implemented, and */
|
|
/* always return EPERM to the caller */
|
|
case S_PHYS:
|
|
case S_PROF:
|
|
case S_PTRACE:
|
|
case S_ACCT:
|
|
case S_MOUNT:
|
|
case S_UMOUNT:
|
|
case S_TIMES:
|
|
i=-1; errno=EPERM; break;
|
|
|
|
/* These syscalls are ignored, and */
|
|
/* always return C=0 to the caller */
|
|
case S_LOCK:
|
|
case S_STIME:
|
|
case S_BREAK:
|
|
i=0; break;
|
|
case S_SYNC:
|
|
sync(); i=0; break;
|
|
|
|
case S_SIGNAL:
|
|
i= v7signal(uarg1, uarg2);
|
|
break;
|
|
case S_EXIT:
|
|
exit(regs[0]);
|
|
i=-1; errno=EPERM; break;
|
|
case S_NICE:
|
|
i= nice(regs[0]); break;
|
|
case S_PAUSE:
|
|
i = pause(); break;
|
|
case S_DUP:
|
|
if (sarg1 > 0100) {
|
|
sarg1 -= 0100;
|
|
i = dup2(sarg1, sarg2); /* Check that sarg2, not r1, holds */
|
|
#ifdef STREAM_BUFFERING
|
|
if ((i!=-1) && ValidFD(sarg2) && ValidFD(sarg1) && stream[sarg1]) {
|
|
fmode= streammode[sarg1];
|
|
stream[sarg2] = fdopen(sarg2, fmode);
|
|
streammode[sarg2]=fmode;
|
|
}
|
|
#endif
|
|
} else
|
|
i = dup(sarg1);
|
|
#ifdef STREAM_BUFFERING
|
|
if ((i!=-1) && ValidFD(i)&& ValidFD(sarg1) && stream[sarg1]) {
|
|
fmode= streammode[sarg1];
|
|
stream[i] = fdopen(i, fmode);
|
|
streammode[i]=fmode;
|
|
}
|
|
#endif
|
|
break;
|
|
case S_TIME:
|
|
i = time(&larg);
|
|
|
|
if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
|
|
fixv6time(&larg); /* Fix annoying bug in V5/V6 ctime() */
|
|
}
|
|
regs[1] = larg & 0xffff;
|
|
i = larg >> 16;
|
|
break;
|
|
case S_ALARM:
|
|
i = alarm(uarg1); break;
|
|
case S_UMASK:
|
|
i = umask(uarg1); break;
|
|
case S_LSEEK:
|
|
/* Work out the args before we do the lseek */
|
|
if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
|
|
whence=uarg3;
|
|
switch (uarg3) {
|
|
case 0: larg= uarg2; break;
|
|
case 1:
|
|
case 2: larg= sarg2; break;
|
|
case 3: whence=0; larg= 512 * uarg2; break;
|
|
case 4: whence=1; larg= 512 * sarg2; break;
|
|
case 5: whence=2; larg= 512 * sarg2; break;
|
|
}
|
|
} else {
|
|
larg = (uarg2 << 16) | uarg3;
|
|
whence= uarg4;
|
|
}
|
|
#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 ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
|
|
if (i!=-1) i=0;
|
|
break;
|
|
}
|
|
regs[1] = i & 0xffff;
|
|
i = i >> 16;
|
|
break;
|
|
case S_READ:
|
|
buf = &dspace[uarg2];
|
|
#ifdef STREAM_BUFFERING
|
|
if (ValidFD(sarg1) && stream[sarg1])
|
|
i = fread(buf, 1, uarg3, stream[sarg1]);
|
|
else
|
|
#endif
|
|
i = read(sarg1, buf, uarg3);
|
|
TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
|
|
break;
|
|
case S_LINK:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
buf2 = xlate_filename(&dspace[uarg2]);
|
|
if (!strcmp(buf, buf2)) i=0; /* Happens on mkdir(1) */
|
|
else i = link(buf, buf2);
|
|
break;
|
|
case S_ACCESS:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
i = access(buf, sarg2);
|
|
break;
|
|
case S_WRITE:
|
|
buf = &dspace[uarg2];
|
|
#ifdef STREAM_BUFFERING
|
|
if (ValidFD(sarg1) && stream[sarg1])
|
|
i = fwrite(buf, 1, uarg3, stream[sarg1]);
|
|
else
|
|
#endif
|
|
i = write(sarg1, buf, uarg3);
|
|
TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
|
|
break;
|
|
case S_CLOSE:
|
|
#ifdef STREAM_BUFFERING
|
|
if (ValidFD(sarg1) && stream[sarg1]) {
|
|
i = fclose(stream[sarg1]);
|
|
stream[sarg1] = NULL;
|
|
} else
|
|
#endif
|
|
i = close(sarg1);
|
|
TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
|
|
break;
|
|
case S_GTTY:
|
|
i = trap_gtty(uarg1, uarg2); break;
|
|
case S_STTY:
|
|
i = trap_stty(uarg1, uarg2); break;
|
|
case S_IOCTL:
|
|
switch (uarg2) {
|
|
case (('t' << 8) + 8): /* GTTY */
|
|
i = trap_gtty(uarg1, uarg3); break;
|
|
case (('t' << 8) + 9): /* STTY */
|
|
i = trap_stty(uarg1, uarg3); break;
|
|
default:
|
|
i=0;
|
|
}
|
|
break;
|
|
case S_FTIME:
|
|
buf = &dspace[uarg1];
|
|
tb = (struct tr_timeb *) buf;
|
|
i = gettimeofday(&tv, &tz);
|
|
if (i == -1) break;
|
|
copylong(tb->time, tv.tv_sec);
|
|
#if 0
|
|
buf = (char *) &(tb->time);
|
|
buf2 = (char *) &(tv.tv_sec);
|
|
buf[0] = buf2[2]; buf[1] = buf2[3]; buf[2] = buf2[0]; buf[3] = buf2[1];
|
|
#endif
|
|
tb->millitm = tv.tv_usec / 1000;
|
|
tb->timezone = tz.tz_minuteswest;
|
|
tb->dstflag = tz.tz_dsttime;
|
|
break;
|
|
case S_STAT:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
if (buf[0]=='\0') buf="."; /* Not documented anywhere */
|
|
if (uarg1==0) buf=".";
|
|
buf2 = &dspace[uarg2];
|
|
i = stat(buf, &stbuf);
|
|
TrapDebug((dbg_file, " on %s return %d ",buf,i));
|
|
goto dostat;
|
|
case S_FSTAT:
|
|
buf2 = &dspace[uarg2];
|
|
i = fstat(sarg1, &stbuf);
|
|
TrapDebug((dbg_file, " on fd %d return %d ",sarg1,i));
|
|
|
|
dostat:
|
|
if (i == -1) break;
|
|
/* V6 and V7 have different stats */
|
|
if ((Binary==IS_A68 || Binary==IS_V6) || (Binary==IS_V5)) {
|
|
t6 = (struct tr_v6stat *) buf2;
|
|
t6->idev = stbuf.st_dev;
|
|
t6->inum = stbuf.st_ino;
|
|
t6->iflags = stbuf.st_mode;
|
|
t6->inl = stbuf.st_nlink;
|
|
t6->iuid = stbuf.st_uid;
|
|
t6->igid = stbuf.st_gid;
|
|
t6->isize = (u_int16_t) (stbuf.st_size & 0xffff);
|
|
t6->isize0 = (u_int8_t) ((stbuf.st_size>>16) & 0xff);
|
|
/* Fix annoying bug in V5/V6 ctime() */
|
|
fixv6time(&(stbuf.st_atime));
|
|
fixv6time(&(stbuf.st_mtime));
|
|
copylong(t6->atime, stbuf.st_atime);
|
|
copylong(t6->mtime, stbuf.st_mtime);
|
|
#if 0
|
|
buf = (char *) &(t6->atime);
|
|
buf2 = (char *) &(stbuf.st_atime);
|
|
buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
|
|
buf = (char *) &(t6->mtime);
|
|
buf2 = (char *) &(stbuf.st_mtime);
|
|
buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
|
|
#endif
|
|
} else {
|
|
t = (struct tr_v7stat *) buf2;
|
|
t->st_dev = stbuf.st_dev;
|
|
t->st_ino = stbuf.st_ino;
|
|
t->st_mode = stbuf.st_mode;
|
|
t->st_nlink = stbuf.st_nlink;
|
|
t->st_uid = stbuf.st_uid;
|
|
t->st_gid = stbuf.st_gid;
|
|
t->st_rdev = stbuf.st_rdev;
|
|
copylong(t->st_size, stbuf.st_size);
|
|
copylong(t->st_atim, stbuf.st_atime);
|
|
copylong(t->st_mtim, stbuf.st_mtime);
|
|
copylong(t->st_ctim, stbuf.st_ctime);
|
|
#if 0
|
|
buf = (char *) &(t->st_size);
|
|
buf2 = (char *) &(stbuf.st_size);
|
|
buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
|
|
buf = (char *) &(t->st_atim);
|
|
buf2 = (char *) &(stbuf.st_atime);
|
|
buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
|
|
buf = (char *) &(t->st_mtim);
|
|
buf2 = (char *) &(stbuf.st_mtime);
|
|
buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
|
|
buf = (char *) &(t->st_ctim);
|
|
buf2 = (char *) &(stbuf.st_ctime);
|
|
buf[0]= buf2[2]; buf[1]= buf2[3]; buf[2]= buf2[0]; buf[3]= buf2[1];
|
|
#endif
|
|
}
|
|
break;
|
|
case S_UTIME:
|
|
utv[0].tv_usec = utv[1].tv_usec = 0;
|
|
copylong(dspace[uarg2], utv[0].tv_sec);
|
|
copylong(dspace[uarg2+4], utv[1].tv_sec);
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
#if 0
|
|
buf2 = &dspace[uarg2];
|
|
buf3 = (char *) &(utv[0].tv_sec);
|
|
buf3[0]= buf2[2]; buf3[1]= buf2[3]; buf3[2]= buf2[0]; buf3[3]= buf2[1];
|
|
|
|
buf2 += 4;
|
|
buf3 = (char *) &(utv[1].tv_sec);
|
|
buf3[0]= buf2[2]; buf3[1]= buf2[3]; buf3[2]= buf2[0]; buf3[3]= buf2[1];
|
|
#endif
|
|
|
|
i = utimes(buf, utv); break;
|
|
case S_UNLINK:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
i = unlink(buf); break;
|
|
case S_OPEN:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
|
|
i = stat(buf, &stbuf); /* If file is a directory */
|
|
if (i == 0 && (stbuf.st_mode & S_IFDIR)) {
|
|
i = open_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));
|
|
}
|
|
|
|
#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 S_MKNOD:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
|
|
if ((uarg2 & 077000) == 040000) {
|
|
/* It's a directory creation */
|
|
i= mkdir(buf, uarg2 & 0777);
|
|
} else
|
|
i = mknod(buf, uarg2, sarg3);
|
|
break;
|
|
case S_CHMOD:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
i = chmod(buf, uarg2); break;
|
|
case S_KILL:
|
|
i = kill(sarg1, sarg2); break;
|
|
case S_CHOWN:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
i = chown(buf, sarg2, sarg3); break;
|
|
case S_PIPE:
|
|
i = pipe(pfd);
|
|
if (i == -1) break;
|
|
#ifdef STREAM_BUFFERING
|
|
if (ValidFD(pfd[0])) {
|
|
stream[pfd[0]] = fdopen(pfd[0], "r");
|
|
streammode[pfd[0]]= "r";
|
|
}
|
|
if (ValidFD(pfd[1])) {
|
|
stream[pfd[1]] = fdopen(pfd[1], "w");
|
|
streammode[pfd[1]]= "w";
|
|
}
|
|
#endif
|
|
i = pfd[0]; regs[1] = pfd[1]; break;
|
|
case S_CHROOT:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
if (buf == NULL) { i=-1; errno=ENOENT; break; }
|
|
set_apout_root(buf);
|
|
i=0; break;
|
|
case S_CHDIR:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
i = chdir(buf); break;
|
|
case S_CREAT:
|
|
buf = xlate_filename(&dspace[uarg1]);
|
|
i = creat(buf, sarg2);
|
|
#ifdef STREAM_BUFFERING
|
|
if (i==-1) break;
|
|
if (ValidFD(i)) {
|
|
stream[i] = fdopen(i, "w");
|
|
streammode[i]= "w";
|
|
}
|
|
#endif
|
|
break;
|
|
case S_EXECE:
|
|
i= trap_exec(1); break;
|
|
|
|
case S_EXEC:
|
|
i= trap_exec(0); break;
|
|
case S_WAIT:
|
|
i = wait(&pid);
|
|
if (i == -1) break;
|
|
regs[1] = pid; break;
|
|
case S_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;
|
|
}
|
|
break;
|
|
case S_GETUID:
|
|
i = geteuid(); regs[1] = i;
|
|
i = getuid(); break;
|
|
case S_GETPID:
|
|
i = getpid(); break;
|
|
case S_GETGID:
|
|
i = getegid(); regs[1] = i;
|
|
i = getgid(); break;
|
|
case S_SETUID:
|
|
i = setuid(sarg1); break;
|
|
case S_SETGID:
|
|
i = setgid(sarg1); break;
|
|
default:
|
|
if (trapnum>S_CHROOT) {
|
|
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",
|
|
v7trap_name[trapnum]);
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
/* Set r0 to either errno or i, */
|
|
/* and clear/set C bit */
|
|
|
|
if (i == -1) {
|
|
SET_CC_C();
|
|
TrapDebug((dbg_file, "errno is %s\n", strerror(errno)));
|
|
} else {
|
|
CLR_CC_C(); regs[0]=i;
|
|
#ifdef DEBUG
|
|
if (trap_debug) {
|
|
fprintf(dbg_file, "return %d\n", i);
|
|
fflush(dbg_file);
|
|
}
|
|
#endif
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/* Translate V7 signal value to our value. */
|
|
static int v7sig[] = {
|
|
0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGIOT, SIGEMT,
|
|
SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS, SIGPIPE, SIGALRM, SIGTERM
|
|
};
|
|
|
|
static int
|
|
trap_exec(int want_env)
|
|
{
|
|
int i;
|
|
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));
|
|
|
|
for (i=0;i<V7_NSIG;i++) signal(v7sig[i], SIG_DFL);
|
|
|
|
cptr=uarg2;
|
|
|
|
Argc=0; Envc=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 (want_env) {
|
|
cptr=uarg3;
|
|
while (Envc < MAX_ARGS) {
|
|
ll_word(cptr, cptr2);
|
|
if (cptr2 == 0)
|
|
break;
|
|
buf = &dspace[cptr2];
|
|
Envp[Envc++] = strdup(buf);
|
|
cptr += 2;
|
|
}
|
|
}
|
|
Envp[Envc] = NULL;
|
|
|
|
if (load_a_out(name, origpath, want_env) == -1) {
|
|
for (Argc--; Argc >= 0; Argc--) free(Argv[Argc]);
|
|
for (Envc--; Envc >= 0; Envc--) free(Envp[Envc]);
|
|
errno= ENOENT; return(-1);
|
|
}
|
|
run(); /* Ok, so it's recursive, I dislike setjmp */
|
|
return(0);
|
|
}
|
|
|
|
/* 7th 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
|
|
open_dir(char *name)
|
|
{
|
|
DIR *d;
|
|
char *tmpname;
|
|
int i;
|
|
struct dirent *dent;
|
|
|
|
struct old_direct {
|
|
int16_t d_ino;
|
|
int8_t d_name[14];
|
|
} odent;
|
|
|
|
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) {
|
|
odent.d_ino = dent->d_fileno;
|
|
strncpy(odent.d_name, dent->d_name, 14);
|
|
write(i, &odent, 16);
|
|
}
|
|
closedir(d);
|
|
lseek(i, 0, SEEK_SET);
|
|
return (i);
|
|
}
|
|
|
|
static int
|
|
trap_gtty(u_int16_t fd, u_int16_t ucnt)
|
|
{
|
|
struct tr_sgttyb *sgtb; /* used in GTTY/STTY */
|
|
struct termios tios; /* used in GTTY/STTY */
|
|
int i;
|
|
|
|
i = tcgetattr(fd, &tios);
|
|
if (i == -1)
|
|
return i;
|
|
CLR_CC_C();
|
|
sgtb = (struct tr_sgttyb *) & dspace[ucnt];
|
|
sgtb->sg_ispeed = tios.c_ispeed;
|
|
sgtb->sg_ospeed = tios.c_ospeed;
|
|
sgtb->sg_erase = tios.c_cc[VERASE];
|
|
sgtb->sg_kill = tios.c_cc[VKILL];
|
|
sgtb->sg_flags = 0;
|
|
if (tios.c_oflag & OXTABS)
|
|
sgtb->sg_flags |= TR_XTABS;
|
|
if (tios.c_cflag & PARENB) {
|
|
if (tios.c_cflag & PARODD)
|
|
sgtb->sg_flags |= TR_ODDP;
|
|
else
|
|
sgtb->sg_flags |= TR_EVENP;
|
|
} else
|
|
sgtb->sg_flags |= TR_ANYP;
|
|
if (tios.c_oflag & ONLCR)
|
|
sgtb->sg_flags |= TR_CRMOD;
|
|
if (tios.c_lflag & ECHO)
|
|
sgtb->sg_flags |= TR_ECHO;
|
|
if (!(tios.c_lflag & ICANON)) {
|
|
if (!(tios.c_lflag & ECHO))
|
|
sgtb->sg_flags |= TR_CBREAK;
|
|
else
|
|
sgtb->sg_flags |= TR_RAW;
|
|
}
|
|
return 0;
|
|
}
|
|
static int
|
|
trap_stty(u_int16_t fd, u_int16_t ucnt)
|
|
{
|
|
struct tr_sgttyb *sgtb; /* used in GTTY/STTY */
|
|
struct termios tios; /* used in GTTY/STTY */
|
|
int i;
|
|
|
|
if (ucnt != 0) {
|
|
sgtb = (struct tr_sgttyb *) & dspace[ucnt];
|
|
tios.c_ispeed = sgtb->sg_ispeed;
|
|
tios.c_ospeed = sgtb->sg_ospeed;
|
|
tios.c_cc[VERASE] = sgtb->sg_erase;
|
|
tios.c_cc[VKILL] = sgtb->sg_kill;
|
|
if (sgtb->sg_flags & TR_XTABS)
|
|
tios.c_oflag |= OXTABS;
|
|
if (sgtb->sg_flags & TR_ODDP) {
|
|
tios.c_cflag |= PARENB;
|
|
tios.c_cflag &= ~PARODD;
|
|
}
|
|
if (sgtb->sg_flags & TR_EVENP)
|
|
tios.c_cflag |= PARENB | PARODD;
|
|
if (sgtb->sg_flags & TR_ANYP)
|
|
tios.c_cflag &= ~PARENB;
|
|
if (sgtb->sg_flags & TR_CRMOD)
|
|
tios.c_oflag |= ONLCR;
|
|
if (sgtb->sg_flags & TR_ECHO)
|
|
tios.c_lflag |= ECHO;
|
|
if (sgtb->sg_flags & TR_RAW) {
|
|
tios.c_lflag &= (~ICANON) & (~ECHO);
|
|
for (i = 0; i < NCCS; i++)
|
|
tios.c_cc[i] = 0;
|
|
tios.c_cc[VMIN] = 1;
|
|
}
|
|
if (sgtb->sg_flags & TR_CBREAK) {
|
|
tios.c_lflag &= (~ICANON);
|
|
tios.c_lflag |= ECHO;
|
|
for (i = 0; i < NCCS; i++)
|
|
tios.c_cc[i] = 0;
|
|
tios.c_cc[VMIN] = 1;
|
|
}
|
|
i = tcsetattr(fd, TCSANOW, &tios);
|
|
return (i);
|
|
} else
|
|
return (-1);
|
|
}
|
|
|
|
|
|
/* Where possible, deal with signals */
|
|
static int v7signal(int sig, int val)
|
|
{
|
|
if (sig>V7_NSIG) { errno=EINVAL; return(-1); }
|
|
if (v7sig[sig]==0) return(0);
|
|
|
|
switch(val) {
|
|
case V7_SIG_IGN:
|
|
return((int)signal(v7sig[sig], SIG_IGN));
|
|
case V7_SIG_DFL:
|
|
return((int)signal(v7sig[sig], SIG_DFL));
|
|
default:
|
|
return(0); /* No handling of this as yet */
|
|
}
|
|
}
|
|
|
|
/* Workaround for bug in V5/V6 ctime() */
|
|
static void fixv6time(time_t *t)
|
|
{
|
|
struct tm *T;
|
|
|
|
T=gmtime(t);
|
|
if (T->tm_year>98) T->tm_year=98;
|
|
*t=timegm(T);
|
|
}
|