1137 lines
24 KiB
C
1137 lines
24 KiB
C
/*
|
|
The MON instruction
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#include "sysidf.h"
|
|
#include "io.h"
|
|
#include "log.h"
|
|
#include "alloc.h"
|
|
#include "shadow.h"
|
|
#include "m_sigtrp.h"
|
|
#include "monstruct.h"
|
|
#include "whatever.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/times.h>
|
|
#include <sys/wait.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <utime.h>
|
|
|
|
extern int running; /* from main.c */
|
|
extern int fd_limit; /* from io.c */
|
|
|
|
#define good_fd(fd) (fd < fd_limit ? 1 : (errno = 9 /* EBADF */, 0))
|
|
|
|
#ifdef BSD_X /* from system.h */
|
|
#include <sys/timeb.h>
|
|
#endif /* BSD_X */
|
|
#ifdef SYS_V
|
|
struct timeb { /* non-existing; we use an ad-hoc definition */
|
|
long time;
|
|
unsigned short millitm;
|
|
short timezone, dstflag;
|
|
};
|
|
#endif /* SYS_V */
|
|
|
|
#ifdef BSD4_2 /* from system.h */
|
|
#include <sys/time.h>
|
|
#endif /* BSD4_2 */
|
|
|
|
#ifdef SYS_V
|
|
#include <fcntl.h>
|
|
#endif /* SYS_V */
|
|
|
|
#include <em_abs.h>
|
|
#include "logging.h"
|
|
#include "global.h"
|
|
#include "trap.h"
|
|
#include "warn.h"
|
|
#include "mem.h"
|
|
|
|
/* Detect supported system calls. */
|
|
|
|
#if !defined __CYGWIN__
|
|
#define HAS_ACCT 1
|
|
#else
|
|
#define HAS_ACCT 0
|
|
#endif
|
|
|
|
#define INPUT 0
|
|
#define OUTPUT 1
|
|
|
|
#define DUPMASK 0x40
|
|
|
|
#define INT2SIZE max(wsize, 2L)
|
|
#define INT4SIZE max(wsize, 4L)
|
|
|
|
#define pop_int() ((int) swpop())
|
|
#define pop_int2() ((int) spop(INT2SIZE))
|
|
#define pop_int4() (spop(INT4SIZE))
|
|
#define pop_intp() ((int) spop(psize))
|
|
#define pop_uns2() ((unsigned int) upop(INT2SIZE))
|
|
#define pop_unsp() ((unsigned int) upop(psize))
|
|
#define pop_ptr() (dppop())
|
|
|
|
#define push_int(a) (wpush((long)(a)))
|
|
#define push_i2(a) (npush((long)(a), INT2SIZE))
|
|
#define push_i4(a) (npush((long)(a), INT4SIZE))
|
|
#define push_unsp(a) (npush((long)(a), psize))
|
|
|
|
#define push_err() { push_int(errno); push_int(errno); }
|
|
|
|
/************************************************************************
|
|
* Monitor calls. *
|
|
* *
|
|
* The instruction "MON" expects a wsized integer on top of *
|
|
* top of the stack, which identifies the call. Often there *
|
|
* are also parameters following this number. The parameters *
|
|
* were stacked in reverse order (C convention). *
|
|
* The possible parameter types are : *
|
|
* *
|
|
* 1) int : integer of wordsize *
|
|
* 2) int2: integer with size max(2, wordsize) *
|
|
* 3) int4: integer with size max(4, wordsize) *
|
|
* 4) intp: integer with size of a pointer *
|
|
* 5) uns2: unsigned integer with size max(2, wordsize) *
|
|
* 6) unsp: unsigned integer with size of a pointer *
|
|
* 7) ptr : pointer into data space *
|
|
* *
|
|
* After the call has been executed, a return code is present *
|
|
* on top of the stack. If this return code equals zero, the call *
|
|
* succeeded and the results of the call can be found right *
|
|
* after the return code. A non zero return code indicates a *
|
|
* failure. In this case no results are available and the return *
|
|
* code has been pushed twice. *
|
|
* *
|
|
* Monitor calls such as "ioctl", "stat", "ftime", etc. work *
|
|
* with a private buffer to be filled by the call. The fields *
|
|
* of the buffer are written to EM-memory separately, possibly *
|
|
* with some of the fields aligned. To this end a number of *
|
|
* transport routines are assembled in monstruct.[ch]. *
|
|
* *
|
|
* The EM report specifies a list of UNIX Version 7 -like system *
|
|
* calls, not full access to the system calls on the underlying *
|
|
* machine. Therefore an attempt has been made to use or emulate *
|
|
* the Version 7 system calls on the various machines. A number *
|
|
* of 4.1 BSD specific parameters have also been implemented. *
|
|
* *
|
|
************************************************************************/
|
|
|
|
PRIVATE size buf_cnt[5]; /* Current sizes of the buffers */
|
|
PRIVATE char *buf[5]; /* Pointers to the buffers */
|
|
|
|
PRIVATE check_buf();
|
|
PRIVATE int savestr(int n, ptr addr);
|
|
PRIVATE int vec();
|
|
|
|
void moncall(void)
|
|
{
|
|
int n; /* number actually read/written */
|
|
int status; /* status for wait-call */
|
|
int flag; /* various flag parameters */
|
|
int mode; /* various mode parameters */
|
|
mode_t oldmask; /* for umask call */
|
|
int whence; /* parameter for lseek */
|
|
int address; /* address parameter typed int2 */
|
|
int owner; /* owner parameter typed int2 */
|
|
int group; /* group parameter typed int2 */
|
|
int pid; /* pid parameter typed int2 */
|
|
int ppid; /* parent process pid */
|
|
long off; /* offset parameter */
|
|
int pfds[2]; /* pipe file descriptors */
|
|
long tm; /* for stime call */
|
|
long actime, modtime; /* for utime */
|
|
int incr; /* for nice call */
|
|
int fd, fdnew; /* file descriptors */
|
|
int groupid; /* group id */
|
|
int userid; /* user id */
|
|
int sig; /* killing signal */
|
|
ptr dsp1, dsp2, dsp3; /* Data Space Pointers */
|
|
int nbytes; /* number to be read/written */
|
|
unsigned int seconds; /* for alarm call */
|
|
int trap_no; /* for sigtrp; trap number */
|
|
int old_trap_no; /* for sigtrp; old trap number */
|
|
int sig_no; /* for sigtrp; signal number */
|
|
int request; /* ioctl and ptrace request */
|
|
char **envvec; /* environment vector (exec) */
|
|
char **argvec; /* argument vector (exec) */
|
|
|
|
struct stat st_buf; /* private stat buffer */
|
|
struct tms tm_buf; /* private tms buffer */
|
|
struct timeb tb_buf; /* private timeb buffer */
|
|
|
|
#ifdef BSD4_2 /* from system.h */
|
|
struct timeval tv; /* private timeval buffer */
|
|
#endif /* BSD4_2 */
|
|
|
|
#ifdef SYS_V /* from system.h */
|
|
struct {time_t x, y;} utimbuf; /* private utime buffer */
|
|
#else /* SYS_V */
|
|
time_t utimbuf[2]; /* private utime buffer */
|
|
#endif /* !SYS_V */
|
|
|
|
char *cp;
|
|
int nr;
|
|
ptr addr;
|
|
int rc;
|
|
|
|
switch (pop_int()) {
|
|
|
|
case 1: /* Exit */
|
|
|
|
#ifdef LOGGING
|
|
ES_def =
|
|
((st_sh(SP) == UNDEFINED)
|
|
|| (st_sh(SP + wsize-1) == UNDEFINED)) ?
|
|
UNDEFINED : DEFINED;
|
|
#else
|
|
ES_def = DEFINED;
|
|
#endif /* LOGGING */
|
|
ES = pop_int();
|
|
running = 0; /* stop the machine */
|
|
LOG(("@m9 Exit: ES = %ld", ES));
|
|
break;
|
|
|
|
case 2: /* Fork */
|
|
|
|
ppid = getpid();
|
|
if ((pid = fork()) == 0) {
|
|
/* Child */
|
|
init_ofiles(0); /* Reinitialize */
|
|
push_int(ppid); /* Pid of parent */
|
|
push_int(1); /* Flag = 1 for child */
|
|
push_int(0);
|
|
LOG(("@m9 Fork: in child, ppid = %d", ppid));
|
|
}
|
|
else if (pid > 0) { /* Parent */
|
|
incr_mess_id(); /* Incr. id for next child */
|
|
push_int(pid); /* Pid of child */
|
|
push_int(0); /* Flag = 0 for parent */
|
|
push_int(0);
|
|
LOG(("@m9 Fork: in parent, cpid = %d", pid));
|
|
}
|
|
else {
|
|
/* fork call failed */
|
|
push_err();
|
|
LOG(("@m4 Fork: failed, pid = %d, errno = %d",
|
|
pid, errno));
|
|
}
|
|
break;
|
|
|
|
case 3: /* Read */
|
|
|
|
fd = pop_int();
|
|
dsp1 = pop_ptr();
|
|
nbytes = pop_intp();
|
|
|
|
if (!good_fd(fd))
|
|
goto read_error;
|
|
if (nbytes < 0) {
|
|
errno = 22; /* EINVAL */
|
|
goto read_error;
|
|
}
|
|
|
|
check_buf(0, (size)nbytes);
|
|
if ((n = read(fd, buf[0], nbytes)) == -1)
|
|
goto read_error;
|
|
|
|
#ifdef LOGGING
|
|
if (check_log("@m6")) {
|
|
register int i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
LOG(("@m6 Read: char = '%c'", *(buf[0] + i)));
|
|
}
|
|
}
|
|
#endif /* LOGGING */
|
|
|
|
if (in_gda(dsp1) && !in_gda(dsp1 + (n-1))) {
|
|
efault(WRGDAH);
|
|
goto read_error;
|
|
}
|
|
|
|
if (!is_in_mem(dsp1, n)) {
|
|
efault(WRUMEM);
|
|
goto read_error;
|
|
}
|
|
|
|
for ( nr = n, cp = buf[0], addr = dsp1;
|
|
nr;
|
|
nr--, addr++, cp++
|
|
) {
|
|
if (in_stack(addr)) {
|
|
ch_st_prot(addr);
|
|
stack_loc(addr) = *cp;
|
|
st_int(addr);
|
|
}
|
|
else {
|
|
ch_dt_prot(addr);
|
|
data_loc(addr) = *cp;
|
|
dt_int(addr);
|
|
}
|
|
}
|
|
|
|
push_unsp(n);
|
|
push_int(0);
|
|
LOG(("@m9 Read: succeeded, n = %d", n));
|
|
break;
|
|
|
|
read_error:
|
|
push_err();
|
|
LOG(("@m4 Read: failed, n = %d, errno = %d", n, errno));
|
|
break;
|
|
|
|
case 4: /* Write */
|
|
|
|
fd = pop_int();
|
|
dsp1 = pop_ptr();
|
|
nbytes = pop_intp();
|
|
|
|
if (!good_fd(fd))
|
|
goto write_error;
|
|
if (nbytes < 0) {
|
|
errno = 22; /* EINVAL */
|
|
goto read_error;
|
|
}
|
|
|
|
if (in_gda(dsp1) && !in_gda(dsp1 + (nbytes-1))) {
|
|
efault(WWGDAH);
|
|
goto write_error;
|
|
}
|
|
if (!is_in_mem(dsp1, nbytes)) {
|
|
efault(WWUMEM);
|
|
goto write_error;
|
|
}
|
|
|
|
#ifdef LOGGING
|
|
for (addr = dsp1; addr < dsp1 + nbytes; addr++) {
|
|
if (mem_sh(addr) == UNDEFINED) {
|
|
warning(in_stack(addr) ? WWLUNDEF : WWGUNDEF);
|
|
}
|
|
}
|
|
#endif /* LOGGING */
|
|
|
|
check_buf(0, (size)nbytes);
|
|
for ( nr = nbytes, addr = dsp1, cp = buf[0];
|
|
nr;
|
|
nr--, addr++, cp++
|
|
) {
|
|
*cp = mem_loc(addr);
|
|
}
|
|
|
|
#ifdef LOGGING
|
|
if (check_log("@m6")) {
|
|
register int i;
|
|
|
|
for (i = 0; i < nbytes; i++) {
|
|
LOG(("@m6 write: char = '%c'", *(buf[0] + i)));
|
|
}
|
|
}
|
|
#endif /* LOGGING */
|
|
|
|
if ((n = write(fd, buf[0], nbytes)) == -1)
|
|
goto write_error;
|
|
|
|
push_unsp(n);
|
|
push_int(0);
|
|
LOG(("@m9 Write: succeeded, n = %d", n));
|
|
break;
|
|
|
|
write_error:
|
|
push_err();
|
|
LOG(("@m4 Write: failed, n = %d, nbytes = %d, errno = %d",
|
|
n, nbytes, errno));
|
|
break;
|
|
|
|
case 5: /* Open */
|
|
|
|
dsp1 = pop_ptr();
|
|
flag = pop_int();
|
|
if (!savestr(0, dsp1) || (fd = open(buf[0], flag)) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Open: failed, file = %lu, flag = %d, fd = %d, errno = %d",
|
|
dsp1, flag, fd, errno));
|
|
}
|
|
else {
|
|
push_int(fd);
|
|
push_int(0);
|
|
LOG(("@m9 Open: succeeded, file = %lu, flag = %d, fd = %d",
|
|
dsp1, flag, fd));
|
|
}
|
|
break;
|
|
|
|
case 6: /* Close */
|
|
|
|
fd = pop_int();
|
|
if (!good_fd(fd) || close(fd) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Close: failed, fd = %d, errno = %d",
|
|
fd, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Close: succeeded"));
|
|
}
|
|
break;
|
|
|
|
case 7: /* Wait */
|
|
|
|
if ((pid = wait(&status)) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Wait: failed, status = %d, errno = %d",
|
|
status, errno));
|
|
}
|
|
else {
|
|
push_i2(pid);
|
|
push_i2(status);
|
|
push_int(0);
|
|
LOG(("@m9 Wait: succeeded, status = %d, pid = %d",
|
|
status, pid));
|
|
}
|
|
break;
|
|
|
|
case 8: /* Creat */
|
|
|
|
dsp1 = pop_ptr();
|
|
flag = pop_int();
|
|
if (!savestr(0, dsp1) || (fd = creat(buf[0], flag)) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Creat: failed, dsp1 = %lu, flag = %d, errno = %d",
|
|
dsp1, flag, errno));
|
|
}
|
|
else {
|
|
push_int(fd);
|
|
push_int(0);
|
|
LOG(("@m9 Creat: succeeded, fd = %d", fd));
|
|
}
|
|
break;
|
|
|
|
case 9: /* Link */
|
|
|
|
dsp1 = pop_ptr();
|
|
dsp2 = pop_ptr();
|
|
if ( !savestr(0, dsp1)
|
|
|| !savestr(1, dsp2)
|
|
|| link(buf[0], buf[1]) == -1
|
|
) {
|
|
push_err();
|
|
LOG(("@m4 Link: failed, dsp1 = %lu, dsp2 = %lu, errno = %d",
|
|
dsp1, dsp2, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Link: succeeded, dsp1 = %lu, dsp2 = %lu",
|
|
dsp1, dsp2));
|
|
}
|
|
break;
|
|
|
|
case 10: /* Unlink */
|
|
|
|
dsp1 = pop_ptr();
|
|
if (!savestr(0, dsp1) || unlink(buf[0]) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Unlink: failed, dsp1 = %lu, errno = %d",
|
|
dsp1, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Unlink: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
|
|
case 12: /* Chdir */
|
|
|
|
dsp1 = pop_ptr();
|
|
if (!savestr(0, dsp1) || chdir(buf[0]) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Chdir: failed, dsp1 = %lu, errno = %d",
|
|
dsp1, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Chdir: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
|
|
case 14: /* Mknod */
|
|
|
|
dsp1 = pop_ptr();
|
|
mode = pop_int();
|
|
address = pop_int2();
|
|
if (!savestr(0, dsp1) || mknod(buf[0], mode, address) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Mknod: failed, dsp1 = %lu, mode = %d, address = %d, errno = %d",
|
|
dsp1, mode, address, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Mknod: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
|
|
case 15: /* Chmod */
|
|
|
|
dsp1 = pop_ptr();
|
|
mode = pop_int2();
|
|
if (!savestr(0, dsp1) || chmod(buf[0], mode) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Chmod: failed, dsp1 = %lu, mode = %d, errno = %d",
|
|
dsp1, mode, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Chmod: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
|
|
case 16: /* Chown */
|
|
|
|
dsp1 = pop_ptr();
|
|
owner = pop_int2();
|
|
group = pop_int2();
|
|
if (!savestr(0, dsp1) || chown(buf[0], owner, group) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Chown: failed, dsp1 = %lu, owner = %d, group = %d, errno = %d",
|
|
dsp1, owner, group, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Chown: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
|
|
case 18: /* Stat */
|
|
|
|
dsp1 = pop_ptr(); /* points to file-name space */
|
|
dsp2 = pop_ptr(); /* points to EM-stat-buffer space */
|
|
if ( !savestr(0, dsp1)
|
|
|| stat(buf[0], &st_buf) == -1
|
|
|| !stat2mem(dsp2, &st_buf)
|
|
) {
|
|
push_err();
|
|
LOG(("@m4 Stat: failed, dsp1 = %lu, dsp2 = %lu, errno = %d",
|
|
dsp1, dsp2, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Stat: succeeded, dsp1 = %lu, dsp2 = %lu",
|
|
dsp1, dsp2));
|
|
}
|
|
break;
|
|
|
|
case 19: /* Lseek */
|
|
|
|
fd = pop_int();
|
|
off = pop_int4();
|
|
whence = pop_int();
|
|
LOG(("@m4 Lseek: fd = %d, off = %ld, whence = %d",
|
|
fd, off, whence));
|
|
|
|
if (!good_fd(fd) || (off = lseek(fd, off, whence)) == -1) {
|
|
push_err();
|
|
LOG(("@m9 Lseek: failed, errno = %d", errno));
|
|
}
|
|
else {
|
|
push_i4(off);
|
|
push_int(0);
|
|
LOG(("@m9 Lseek: succeeded, pushed %ld", off));
|
|
}
|
|
break;
|
|
|
|
case 20: /* Getpid */
|
|
|
|
pid = getpid();
|
|
push_i2(pid);
|
|
LOG(("@m9 Getpid: succeeded, pid = %d", pid));
|
|
break;
|
|
|
|
#ifdef WANT_MOUNT_UMOUNT
|
|
case 21: /* Mount */
|
|
|
|
dsp1 = pop_ptr();
|
|
dsp2 = pop_ptr();
|
|
flag = pop_int();
|
|
if ( !savestr(0, dsp1)
|
|
|| !savestr(1, dsp2)
|
|
|| mount(buf[0], buf[1], flag) == -1
|
|
) {
|
|
push_err();
|
|
LOG(("@m4 Mount: failed, dsp1 = %lu, dsp2 = %lu, flag = %d, errno = %d",
|
|
dsp1, dsp2, flag, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Mount: succeeded, dsp1 = %lu, dsp2 = %lu, flag = %d",
|
|
dsp1, dsp2, flag));
|
|
}
|
|
break;
|
|
|
|
case 22: /* Umount */
|
|
|
|
dsp1 = pop_ptr();
|
|
if ( !savestr(0, dsp1)
|
|
#ifndef BSD4_2 /* from system.h */
|
|
|| umount(buf[0]) == -1
|
|
#else /* BSD4_2 */
|
|
|| unmount(buf[0]) == -1
|
|
#endif /* BSD4_2 */
|
|
) {
|
|
push_err();
|
|
LOG(("@m4 Umount: failed, dsp1 = %lu, errno = %d",
|
|
dsp1, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Mount: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case 23: /* Setuid */
|
|
|
|
userid = pop_int2();
|
|
if (setuid(userid) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Setuid: failed, userid = %d, errno = %d",
|
|
userid, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Setuid: succeeded, userid = %d", userid));
|
|
}
|
|
break;
|
|
|
|
case 24: /* Getuid */
|
|
|
|
userid = getuid();
|
|
push_i2(userid);
|
|
LOG(("@m9 Getuid(part 1): real uid = %d", userid));
|
|
userid = geteuid();
|
|
push_i2(userid);
|
|
LOG(("@m9 Getuid(part 2): eff uid = %d", userid));
|
|
break;
|
|
|
|
#ifdef WANT_STIME
|
|
case 25: /* Stime */
|
|
|
|
tm = pop_int4();
|
|
#ifndef BSD4_2 /* from system.h */
|
|
rc = stime(&tm);
|
|
#else /* BSD4_2 */
|
|
tv.tv_sec = tm;
|
|
tv.tv_usec = 0; /* zero microseconds */
|
|
rc = settimeofday(&tv, (struct timezone *)0);
|
|
#endif /* BSD4_2 */
|
|
if (rc == -1) {
|
|
push_err();
|
|
LOG(("@m4 Stime: failed, tm = %ld, errno = %d",
|
|
tm, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Stime: succeeded, tm = %ld", tm));
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case 26: /* Ptrace */
|
|
|
|
request = pop_int();
|
|
pid = pop_int2();
|
|
dsp3 = pop_ptr();
|
|
n = pop_int(); /* Data */
|
|
einval(WPTRACEIMP);
|
|
push_err();
|
|
LOG(("@m4 Ptrace: failed, request = %d, pid = %d, addr = %lu, data = %d, errno = %d",
|
|
request, pid, dsp3, n, errno));
|
|
break;
|
|
|
|
case 27: /* Alarm */
|
|
|
|
seconds = pop_uns2();
|
|
LOG(("@m9 Alarm(part 1) seconds = %u", seconds));
|
|
seconds = alarm(seconds);
|
|
push_i2(seconds);
|
|
LOG(("@m9 Alarm(part 2) seconds = %u", seconds));
|
|
break;
|
|
|
|
case 28: /* Fstat */
|
|
|
|
fd = pop_int();
|
|
dsp2 = pop_ptr();
|
|
if ( !good_fd(fd)
|
|
|| fstat(fd, &st_buf) == -1
|
|
|| !stat2mem(dsp2, &st_buf)
|
|
) {
|
|
push_err();
|
|
LOG(("@m4 Fstat: failed, fd = %d, dsp2 = %lu, errno = %d",
|
|
fd, dsp2, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Fstat: succeeded, fd = %d, dsp2 = %lu",
|
|
fd, dsp2));
|
|
}
|
|
break;
|
|
|
|
case 29: /* Pause */
|
|
|
|
pause();
|
|
LOG(("@m9 Pause: succeeded"));
|
|
break;
|
|
|
|
case 30: /* Utime */
|
|
|
|
dsp1 = pop_ptr();
|
|
dsp2 = pop_ptr();
|
|
if (memfault(dsp2, 2*INT4SIZE)) {
|
|
push_err();
|
|
LOG(("@m4 Utime: failed, dsp1 = %lu, dsp2 = %lu, errno = %d",
|
|
dsp1, dsp2, errno));
|
|
break;
|
|
}
|
|
actime = mem_ldu(dsp2, INT4SIZE);
|
|
modtime = mem_ldu(dsp2 + INT4SIZE, INT4SIZE);
|
|
#ifdef SYS_V /* from system.h */
|
|
utimbuf.x = actime;
|
|
utimbuf.y = modtime;
|
|
if (!savestr(0, dsp1) || utime(buf[0], (struct utimbuf*) &utimbuf) == -1) {
|
|
#else /* SYS_V */
|
|
utimbuf[0] = actime;
|
|
utimbuf[1] = modtime;
|
|
if (!savestr(0, dsp1) || utime(buf[0], utimbuf) == -1) {
|
|
/* may require modification for POSIX ???!!! */
|
|
#endif /* !SYS_V */
|
|
push_err();
|
|
LOG(("@m4 Utime: failed, dsp1 = %lu, dsp2 = %lu, errno = %d",
|
|
dsp1, dsp2, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Utime: succeeded, dsp1 = %lu, dsp2 = %lu",
|
|
dsp1, dsp2));
|
|
}
|
|
break;
|
|
|
|
case 33: /* Access */
|
|
|
|
dsp1 = pop_ptr();
|
|
mode = pop_int();
|
|
if (!savestr(0, dsp1) || access(buf[0], mode) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Access: failed, dsp1 = %lu, mode = %d, errno = %d",
|
|
dsp1, mode, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Access: succeeded, dsp1 = %lu, mode = %d",
|
|
dsp1, mode));
|
|
}
|
|
break;
|
|
|
|
case 34: /* Nice */
|
|
|
|
incr = pop_int();
|
|
nice(incr);
|
|
LOG(("@m9 Nice: succeeded, incr = %d", incr));
|
|
break;
|
|
|
|
case 35: /* Ftime */
|
|
|
|
dsp2 = pop_ptr();
|
|
#ifdef BSD_X /* from system.h */
|
|
ftime(&tb_buf);
|
|
#endif /* BSD_X */
|
|
#ifdef SYS_V /* from system.h */
|
|
tb_buf.time = time((time_t*)0);
|
|
tb_buf.millitm = 0;
|
|
tb_buf.timezone = timezone / 60;
|
|
tb_buf.dstflag = daylight;
|
|
#endif /* SYS_V */
|
|
if (!timeb2mem(dsp2, &tb_buf)) {
|
|
push_err();
|
|
LOG(("@m4 Ftime: failed, dsp2 = %lu, errno = %d",
|
|
dsp2, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Ftime: succeeded, dsp2 = %lu", dsp2));
|
|
}
|
|
break;
|
|
|
|
case 36: /* Sync */
|
|
|
|
sync();
|
|
LOG(("@m9 Sync: succeeded"));
|
|
break;
|
|
|
|
case 37: /* Kill */
|
|
|
|
pid = pop_int2();
|
|
sig = pop_int();
|
|
if (kill(pid, sig) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Kill: failed, pid = %d, sig = %d, errno = %d",
|
|
pid, sig, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Kill: succeeded, pid = %d, sig = %d",
|
|
pid, sig));
|
|
}
|
|
break;
|
|
|
|
case 41: /* Dup & Dup2 */
|
|
|
|
fd = pop_int();
|
|
fdnew = pop_int();
|
|
if (fd & DUPMASK) {
|
|
int fd1 = fd & ~DUPMASK;/* stripped */
|
|
|
|
LOG(("@m4 Dup2: fd1 = %d, fdnew = %d", fd1, fdnew));
|
|
if (!good_fd(fd1)) {
|
|
fdnew = -1;
|
|
goto dup2_error;
|
|
}
|
|
#ifdef BSD_X /* from system.h */
|
|
fdnew = dup2(fd1, fdnew);
|
|
#endif /* BSD_X */
|
|
|
|
#ifdef SYS_V /* from system.h */
|
|
{
|
|
/* simulating the semantics of dup2 on SYS_V */
|
|
int dupped = dup(fd1);
|
|
|
|
if (dupped < 0 && errno != EMFILE) {
|
|
/* the dup failed, but not
|
|
because of too many open
|
|
file descriptors
|
|
*/
|
|
fdnew = dupped;
|
|
}
|
|
else {
|
|
close(dupped);
|
|
close(fdnew);
|
|
fdnew = fcntl(fd1, F_DUPFD, fdnew);
|
|
}
|
|
}
|
|
#endif /* SYS_V */
|
|
dup2_error:;
|
|
}
|
|
else {
|
|
LOG(("@m4 Dup: fd = %d, fdnew = %d", fd, fdnew));
|
|
fdnew = (!good_fd(fd) ? -1 : dup(fd));
|
|
}
|
|
|
|
if (fdnew == -1) {
|
|
push_err();
|
|
LOG(("@m4 Dup/Dup2: failed, fdnew = %d, errno = %d",
|
|
fdnew, errno));
|
|
}
|
|
else {
|
|
push_int(fdnew);
|
|
push_int(0);
|
|
LOG(("@m9 Dup/Dup2: succeeded, fdnew = %d", fdnew));
|
|
}
|
|
break;
|
|
|
|
case 42: /* Pipe */
|
|
|
|
if (pipe(pfds) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Pipe: failed, errno = %d", errno));
|
|
}
|
|
else {
|
|
push_int(pfds[0]);
|
|
push_int(pfds[1]);
|
|
push_int(0);
|
|
LOG(("@m9 Pipe: succeeded, pfds[0] = %d, pfds[1] = %d",
|
|
pfds[0], pfds[1]));
|
|
}
|
|
break;
|
|
|
|
case 43: /* Times */
|
|
|
|
dsp2 = pop_ptr();
|
|
times(&tm_buf);
|
|
if (!tms2mem(dsp2, &tm_buf)) {
|
|
push_err();
|
|
LOG(("@m4 Times: failed, dsp2 = %lu, errno = %d",
|
|
dsp2, errno));
|
|
}
|
|
else {
|
|
LOG(("@m9 Times: succeeded, dsp2 = %lu", dsp2));
|
|
}
|
|
break;
|
|
|
|
case 44: /* Profil */
|
|
|
|
dsp1 = pop_ptr(); /* Buffer */
|
|
nbytes = pop_intp(); /* Buffer size */
|
|
off = pop_intp(); /* Offset */
|
|
n = pop_intp(); /* Scale */
|
|
einval(WPROFILIMP);
|
|
push_err();
|
|
LOG(("@m4 Profil: failed, dsp1 = %lu, nbytes = %d, offset = %d, scale = %d, errno = %d",
|
|
dsp1, nbytes, off, n, errno));
|
|
break;
|
|
|
|
case 46: /* Setgid */
|
|
|
|
groupid = pop_int2();
|
|
if (setgid(groupid) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Setgid: failed, groupid = %d, errno = %d",
|
|
groupid, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Setgid: succeeded, groupid = %d", groupid));
|
|
}
|
|
break;
|
|
|
|
case 47: /* Getgid */
|
|
|
|
groupid = getgid();
|
|
push_i2(groupid);
|
|
LOG(("@m9 Getgid(part 1): succeeded, real groupid = %d",
|
|
groupid));
|
|
groupid = getegid();
|
|
push_i2(groupid);
|
|
LOG(("@m9 Getgid(part 2): succeeded, eff groupid = %d",
|
|
groupid));
|
|
break;
|
|
|
|
case 48: /* Sigtrp */
|
|
|
|
trap_no = pop_int();
|
|
sig_no = pop_int();
|
|
|
|
if ((old_trap_no = do_sigtrp(trap_no, sig_no)) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Sigtrp: failed, trap_no = %d, sig_no = %d, errno = %d",
|
|
trap_no, sig_no, errno));
|
|
}
|
|
else {
|
|
push_int(old_trap_no);
|
|
push_int(0);
|
|
LOG(("@m9 Sigtrp: succeeded, trap_no = %d, sig_no = %d, old_trap_no = %d",
|
|
trap_no, sig_no, old_trap_no));
|
|
}
|
|
break;
|
|
|
|
case 51: /* Acct */
|
|
|
|
dsp1 = pop_ptr();
|
|
#if HAS_ACCT
|
|
if (!savestr(0, dsp1) || acct(buf[0]) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Acct: failed, dsp1 = %lu, errno = %d",
|
|
dsp1, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Acct: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
#else
|
|
einval(WMPXIMP);
|
|
push_err();
|
|
LOG(("@m4 Acct: failed, request = %d, dsp1 = %lu, errno = %d",
|
|
request, dsp1, errno));
|
|
#endif
|
|
break;
|
|
|
|
case 54: /* Ioctl */
|
|
|
|
fd = pop_int();
|
|
request = pop_int();
|
|
dsp2 = pop_ptr();
|
|
if (!good_fd(fd) || do_ioctl(fd, request, dsp2) != 0) {
|
|
push_err();
|
|
LOG(("@m4 Ioctl: failed, fd = %d, request = %d, dsp2 = %lu, errno = %d",
|
|
fd, request, dsp2, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Ioctl: succeeded, fd = %d, request = %d, dsp2 = %lu",
|
|
fd, request, dsp2));
|
|
}
|
|
break;
|
|
|
|
case 56: /* Mpxcall */
|
|
|
|
request = pop_int(); /* Command */
|
|
dsp1 = pop_ptr(); /* Vec */
|
|
einval(WMPXIMP);
|
|
push_err();
|
|
LOG(("@m4 Mpxcall: failed, request = %d, dsp1 = %lu, errno = %d",
|
|
request, dsp1, errno));
|
|
break;
|
|
|
|
case 59: /* Exec */
|
|
|
|
dsp1 = pop_ptr();
|
|
dsp2 = pop_ptr();
|
|
dsp3 = pop_ptr();
|
|
if ( !savestr(0, dsp1)
|
|
|| !vec(1, 2, dsp2, &argvec)
|
|
|| !vec(3, 4, dsp3, &envvec)
|
|
|| /* execute results, ignore return code */
|
|
(execve(buf[0], argvec, envvec), 1)
|
|
) {
|
|
push_err();
|
|
LOG(("@m4 Exece: failed, dsp1 = %lu, dsp2 = %lu, dsp2 = %lu, errno = %d",
|
|
dsp1, dsp2, dsp3, errno));
|
|
}
|
|
break;
|
|
|
|
case 60: /* Umask */
|
|
|
|
mode = pop_int2();
|
|
oldmask = umask((mode_t)mode);
|
|
push_int(oldmask);
|
|
LOG(("@m9 Umask: succeeded, mode = %d, oldmask = %d",
|
|
mode, oldmask));
|
|
break;
|
|
|
|
case 61: /* Chroot */
|
|
|
|
dsp1 = pop_ptr();
|
|
if (!savestr(0, dsp1) || chroot(buf[0]) == -1) {
|
|
push_err();
|
|
LOG(("@m4 Chroot: failed, dsp1 = %lu, errno = %d",
|
|
dsp1, errno));
|
|
}
|
|
else {
|
|
push_int(0);
|
|
LOG(("@m9 Chroot: succeeded, dsp1 = %lu", dsp1));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
trap(EBADMON);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Buffer administration */
|
|
|
|
PRIVATE check_buf(n, sz)
|
|
int n;
|
|
size sz;
|
|
{
|
|
if (buf_cnt[n] == 0) {
|
|
buf_cnt[n] = max(128, sz);
|
|
buf[n] = Malloc(buf_cnt[n], "moncall buffer");
|
|
}
|
|
else if (buf_cnt[n] < sz) {
|
|
buf_cnt[n] = allocfrac(sz);
|
|
buf[n] = Realloc(buf[n], buf_cnt[n], "moncall buffer");
|
|
}
|
|
}
|
|
|
|
PRIVATE int savestr(int n, ptr addr)
|
|
{
|
|
register size len;
|
|
register char *cp, ch;
|
|
|
|
/* determine the length, carefully */
|
|
len = 0;
|
|
do {
|
|
if (memfault(addr + len, 1L)) {
|
|
return 0;
|
|
}
|
|
ch = mem_loc(addr + len);
|
|
len++;
|
|
} while (ch);
|
|
|
|
/* allocate enough buffer space */
|
|
check_buf(n, len);
|
|
|
|
/* copy the string */
|
|
cp = buf[n];
|
|
do {
|
|
*cp++ = ch = mem_loc(addr);
|
|
addr++;
|
|
} while (ch);
|
|
|
|
return 1;
|
|
}
|
|
|
|
PRIVATE int vec(n1, n2, addr, vecvec)
|
|
int n1, n2;
|
|
ptr addr;
|
|
char ***vecvec;
|
|
{
|
|
register char *cp1, *cp2;
|
|
ptr p, ldp;
|
|
register int n_ent = 0; /* number of entries */
|
|
register size str = 0; /* total string length */
|
|
|
|
/* determine number of elements n_ent */
|
|
p = addr;
|
|
do {
|
|
if (memfault(addr, psize)) {
|
|
return 0;
|
|
}
|
|
ldp = mem_lddp(p);
|
|
if (!savestr(n2, ldp)) {
|
|
return 0;
|
|
}
|
|
str += strlen(buf[n2]) + 1;
|
|
n_ent++;
|
|
p += psize;
|
|
} while (ldp);
|
|
n_ent++;
|
|
|
|
*vecvec = (char **) Malloc((size)(n_ent * sizeof (char *)),
|
|
"argvec or envvec in exec()");
|
|
check_buf(n1, str);
|
|
|
|
/* copy the elements */
|
|
for ( cp1 = buf[n1], n_ent = 0, p = addr;
|
|
(ldp = mem_lddp(p)) != 0;
|
|
p += psize, n_ent++
|
|
) {
|
|
if (!savestr(n2, ldp)) {
|
|
return 0;
|
|
}
|
|
(*vecvec)[n_ent] = cp1;
|
|
cp2 = buf[n2];
|
|
while ((*cp1++ = *cp2++) != '\0') {
|
|
/* nothing */
|
|
}
|
|
}
|
|
(*vecvec)[n_ent] = 0;
|
|
return 1;
|
|
}
|
|
|
|
int memfault(ptr addr, size length)
|
|
{
|
|
/* centralizes (almost) all memory access tests in MON */
|
|
if (!is_in_mem(addr, length)) {
|
|
efault(WMONFLT);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void efault(int wrn /* warning number */)
|
|
{
|
|
warning(wrn);
|
|
errno = 14; /* EFAULT */
|
|
}
|
|
|
|
void einval(int wrn /* warning number */)
|
|
{
|
|
warning(wrn);
|
|
errno = 22; /* EINVAL */
|
|
}
|