mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-12-22 14:30:29 +00:00
1250 lines
32 KiB
C
1250 lines
32 KiB
C
/* $Id: sys.c,v 1.1 1998/02/02 08:19:05 taubert Exp $ */
|
|
|
|
#pragma optimize 79
|
|
segment "KERN2 ";
|
|
|
|
/*
|
|
|
|
sys.c
|
|
|
|
GS/IX Kernel routines for process control
|
|
|
|
Copyright 1991-1998, Procyon, Inc.
|
|
Jawaid Bazyar and Derek Taubert
|
|
*/
|
|
|
|
#include "conf.h"
|
|
#include "proc.h"
|
|
#include "kernel.h"
|
|
#include "gno.h"
|
|
#include "kvm.h"
|
|
#include "sys.h"
|
|
#include "/lang/orca/libraries/orcacdefs/stdio.h"
|
|
#include "/lang/orca/libraries/orcacdefs/string.h"
|
|
#include "/lang/orca/libraries/orcacdefs/stdlib.h"
|
|
#include <loader.h>
|
|
#include <memory.h>
|
|
#include <gsos.h>
|
|
#include <shell.h>
|
|
#include <texttool.h>
|
|
#include <misctool.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/times.h>
|
|
|
|
extern kernelStructPtr kp;
|
|
|
|
/* signal context record */
|
|
typedef struct ctxt {
|
|
word ctx_A;
|
|
word ctx_X;
|
|
word ctx_Y;
|
|
word ctx_state;
|
|
word ctx_D;
|
|
byte ctx_B;
|
|
byte ctx_B1;
|
|
word ctx_P;
|
|
word ctx_S1;
|
|
longword ctx_PC;
|
|
} ctxt, *ctxtPtr;
|
|
|
|
struct GSString1K {
|
|
Word length; /* Number of Chars in text field */
|
|
char text[1024];
|
|
} ;
|
|
typedef struct GSString1K GSString1K, *GSString1KPtr;
|
|
|
|
struct ResultBuf1K {
|
|
Word bufSize;
|
|
GSString1K bufString;
|
|
} ;
|
|
typedef struct ResultBuf1K ResultBuf1K, *ResultBuf1KPtr;
|
|
|
|
/*
|
|
this is the info kept per-process on what sorts of shit the process
|
|
expects for I/O. This is similar to a special case of user.h fd table
|
|
including only the stdin/stdout fds (0-2).
|
|
*/
|
|
|
|
typedef struct ttyinf {
|
|
word InANDMask;
|
|
word InORMask;
|
|
word OutANDMask;
|
|
word OutORMask;
|
|
word ErrANDMask;
|
|
word ErrORMask;
|
|
word InDeviceType;
|
|
word OutDeviceType;
|
|
word ErrDeviceType;
|
|
longword InSlot;
|
|
longword OutSlot;
|
|
longword ErrSlot;
|
|
word dummy;
|
|
} ttyinf;
|
|
|
|
#define NPGRP 32
|
|
|
|
pgrp pgrpInfo[NPGRP];
|
|
typedef struct ttyInfo {
|
|
word pgrp;
|
|
} ttyInfo;
|
|
|
|
extern ttyStruct;
|
|
ttyInfo *ttys = (ttyInfo *) &ttyStruct;
|
|
|
|
#define isbadpgrp(p) ((p < 0) || (p >= NPGRP))
|
|
|
|
static word hiWord(longword w)
|
|
{
|
|
word h;
|
|
|
|
asm {
|
|
lda w+2
|
|
sta h
|
|
}
|
|
return h;
|
|
}
|
|
|
|
static word loWord(longword w)
|
|
{
|
|
word l;
|
|
|
|
asm {
|
|
lda w
|
|
sta l
|
|
}
|
|
return l;
|
|
}
|
|
|
|
void *kmalloc(size_t size)
|
|
{
|
|
handle h;
|
|
word p_uid;
|
|
void *x;
|
|
|
|
/* $$$ p_uid = kp->procTable[Kgetpid()].userID; */
|
|
p_uid = PROC->userID;
|
|
h = NewHandle(size, p_uid, 0xC008, NULL);
|
|
|
|
if (toolerror()) {
|
|
fprintf(stderr, "kmalloc:%04X\n",toolerror());
|
|
return NULL;
|
|
}
|
|
x = *h;
|
|
return x;
|
|
}
|
|
|
|
void *pmalloc(size_t size, word p_uid)
|
|
{
|
|
handle h;
|
|
void *x;
|
|
|
|
h = NewHandle(size, p_uid, 0xC008, NULL);
|
|
|
|
if (toolerror()) {
|
|
fprintf(stderr, "pmalloc:%04X\n",toolerror());
|
|
return NULL;
|
|
}
|
|
x = *h;
|
|
return x;
|
|
}
|
|
|
|
int kfree(void *mem)
|
|
{
|
|
handle h;
|
|
|
|
if (h = (FindHandle(mem) == NULL)) return SYSERR;
|
|
DisposeHandle(h);
|
|
return (OK);
|
|
}
|
|
|
|
static int findEmptyProc(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < NPROC; i++)
|
|
if (kp->procTable[i].processState == procUNUSED) return i;
|
|
return -1;
|
|
}
|
|
|
|
#if 0
|
|
int isbadpid( int pid )
|
|
{
|
|
int mpid;
|
|
|
|
mpid = mapPID(pid);
|
|
if (mpid == -1) return SYSERR;
|
|
else return SYSOK;
|
|
}
|
|
#endif
|
|
|
|
static int createProc(word stack, word dp, longword process)
|
|
{
|
|
int p;
|
|
|
|
disableps();
|
|
/* printf("creating process stack=%04X, dp=%04X, addr=%08lX\n",
|
|
stack, dp, process); */
|
|
p = findEmptyProc();
|
|
if (p == -1) { enableps(); return SYSERR; }
|
|
kp->procTable[p].processState = procSUSPENDED;
|
|
kp->procTable[p].parentpid = Kgetpid();
|
|
kp->procTable[p].irq_S = stack;
|
|
kp->procTable[p].irq_D = dp;
|
|
kp->procTable[p].irq_PC = (word) process;
|
|
kp->procTable[p].irq_B =
|
|
kp->procTable[p].irq_K = (process >> 16);
|
|
kp->procTable[p].irq_P = 4; /* interrupts must be OFF you putz */
|
|
/* assign child same TTY as parent */
|
|
kp->procTable[p].ttyID = PROC->ttyID;
|
|
/* $$$ kp->procTable[Kgetpid()].ttyID; */
|
|
enableps();
|
|
return p;
|
|
}
|
|
|
|
#if 0
|
|
#define BUSY_FLAG ((byte *)0xE100FFl)
|
|
|
|
int _ready(int pid, int resch)
|
|
{
|
|
int mpid;
|
|
unsigned x;
|
|
|
|
mpid = mapPID(pid);
|
|
if (mpid == -1) return SYSERR;
|
|
disableps();
|
|
if (kp->procTable[mpid].processState != procUNUSED)
|
|
kp->procTable[mpid].processState = procREADY;
|
|
if (resch) {
|
|
asm {
|
|
php
|
|
sei
|
|
}
|
|
x = *BUSY_FLAG;
|
|
*BUSY_FLAG = 0;
|
|
_resched();
|
|
*BUSY_FLAG = x;
|
|
asm {
|
|
plp
|
|
}
|
|
}
|
|
enableps();
|
|
return OK;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Allocates a new file descriptor in this process. If the fd table is
|
|
* full, resizes the table and proceeds with the allocation.
|
|
* allocFD does NOT adjust the fdCount field, as it's possible that
|
|
* we must unallocate the fd later due to an error and it saves
|
|
* a bit of code. (i.e. the caller must inc fdCount)
|
|
*/
|
|
fdentryPtr allocFD(int *fdn)
|
|
{
|
|
fdtablePtr ft;
|
|
int i,j;
|
|
unsigned s;
|
|
|
|
/* $$$ ft = kp->procTable[Kgetpid()].openFiles; */
|
|
ft = PROC->openFiles;
|
|
j = 0; /* change this when tables are dynamically allocated */
|
|
disableps();
|
|
retry:
|
|
while (j < ft->fdTableSize) {
|
|
if (ft->fds[j].refNum == 0) {
|
|
ft->fds[j].refNum = -1; /* just to make this item look allocated */
|
|
enableps();
|
|
if (fdn != NULL) *fdn = j+1;
|
|
return &(ft->fds[j]);
|
|
} else j++;
|
|
}
|
|
ft->fdTableSize += 32;
|
|
i = ft->fdTableSize;
|
|
ft = realloc(ft,sizeof(fdtable) + sizeof(fdentry)*(i-1));
|
|
/* zero out the new entries */
|
|
memset(&ft->fds[i-32],0,sizeof(fdentry)*32);
|
|
PROC->openFiles = ft;
|
|
goto retry;
|
|
}
|
|
|
|
struct rc {
|
|
int rn;
|
|
int rt;
|
|
int cn;
|
|
};
|
|
|
|
#ifdef NOTDEFINED
|
|
void printFDS(fdtablePtr f)
|
|
{
|
|
int i;
|
|
struct rc *r;
|
|
extern struct rc *FINDREFNUM(int,int);
|
|
|
|
fputc('[',stderr);
|
|
for (i = 0; i < 32; i++) {
|
|
if (f->fds[i].refNum) {
|
|
fprintf(stderr,"(%d ",i);
|
|
switch (f->fds[i].refType) {
|
|
case rtGSOS: fprintf(stderr,"GSOS "); break;
|
|
case rtPIPE: fprintf(stderr,"PIPE "); break;
|
|
case rtTTY : fprintf(stderr,"TTY "); break;
|
|
default : fprintf(stderr,"%d ",f->fds[i].refType);
|
|
}
|
|
fprintf(stderr,"%d/%d ", f->fds[i].refNum,f->fds[i].refLevel);
|
|
r = FINDREFNUM(f->fds[i].refType,f->fds[i].refNum);
|
|
if (r == NULL) fprintf(stderr,"!!)");
|
|
else fprintf(stderr,"%d)",r->cn);
|
|
}
|
|
}
|
|
fputc(']',stderr); fputc('\n',stderr);
|
|
}
|
|
#endif
|
|
|
|
#pragma databank 1
|
|
void endproc(void)
|
|
{
|
|
/*
|
|
* printfs in here won't work with quiting orca/c progs because ~C_SHUTDOWN
|
|
* closes ALL open file descriptors
|
|
*/
|
|
|
|
/* printf("end of process %d\n",Kgetpid()); */
|
|
/* $$$ kp->procTable[Kgetpid()].flags |= FL_NORMTERM; */
|
|
PROC->flags |= FL_NORMTERM;
|
|
/* kill(kp->procTable[Kgetpid()].flpid,9); */
|
|
Kkill(&errno, 9, PROC->flpid);
|
|
/* not reached */
|
|
PANIC("ENDPROC KILL OVERRUN");
|
|
}
|
|
|
|
int CommonQuit(char *pname, int flag)
|
|
{
|
|
/*struct pentry *p = &kp->procTable[Kgetpid()];*/
|
|
char *pcopy;
|
|
quitStack *qs;
|
|
GSString255Ptr gp;
|
|
|
|
enableps();
|
|
if (flag & 0x4000) PROC->flags |= FL_RESTART;
|
|
if (pname && *pname) {
|
|
if (flag & 0x8000) {
|
|
gp = (GSString255Ptr) LGetPathname2(PROC->userID,1);
|
|
qs = malloc(gp->length+5);
|
|
qs->next = PROC->returnStack;
|
|
memcpy(qs->data,gp->text,gp->length);
|
|
qs->data[gp->length] = 0;
|
|
PROC->returnStack = qs;
|
|
}
|
|
pcopy = kmalloc(strlen(pname)+1);
|
|
strcpy(pcopy,pname); nfree(pname);
|
|
Kexecve(&errno,pcopy,pcopy);
|
|
}
|
|
else {
|
|
if ((qs = PROC->returnStack) != NULL) {
|
|
pcopy = kmalloc(strlen(qs->data)+1);
|
|
strcpy(pcopy,qs->data);
|
|
PROC->returnStack = qs->next; nfree(qs);
|
|
Kexecve(&errno,pcopy,pcopy);
|
|
} else Kkill(&errno, 9, PROC->flpid);
|
|
}
|
|
disableps();
|
|
return 0x27;
|
|
}
|
|
|
|
#pragma toolparms 1
|
|
/* subr is the address to begin the process at */
|
|
|
|
pascal int KERNSetGNOQuitRec(word pCount,GSString255Ptr pathname, word flags, int *ERRNO)
|
|
{
|
|
extern QuitRecGS quitParms;
|
|
quitParms.pCount = pCount;
|
|
quitParms.pathname = pathname;
|
|
quitParms.flags = flags;
|
|
}
|
|
|
|
int KERNgetpid()
|
|
/* get the process id of currently executing process */
|
|
{
|
|
/*$$$ return( kp->procTable[kp->truepid].flpid ); */
|
|
return (PROC->flpid);
|
|
}
|
|
|
|
int KERNgetppid(int *ERRNO)
|
|
/* get the pid of the process' parent */
|
|
{
|
|
return (kp->procTable[PROC->parentpid].flpid);
|
|
}
|
|
|
|
int KERNgetpgrp(int *ERRNO, int pid)
|
|
/* get the pgrp field for a specified process */
|
|
{
|
|
int mpid;
|
|
mpid = mapPID(pid);
|
|
if (mpid == -1) { *ERRNO = ESRCH; return -1; }
|
|
return( kp->procTable[mpid].pgrp );
|
|
}
|
|
|
|
int KERNsetpgrp(int *ERRNO, int pgrp, int pid)
|
|
{
|
|
int mpid;
|
|
int pp;
|
|
|
|
mpid = mapPID(pid);
|
|
if (mpid == -1) { *ERRNO = ESRCH; return -1; }
|
|
if (isbadpgrp(pgrp)) { *ERRNO = ESRCH; return -1; }
|
|
if (kp->procTable[mpid].pgrp != pgrp)
|
|
{
|
|
if (pgrp != 0) pgrpInfo[pgrp-2].pgrpref++;
|
|
if ((pp = kp->procTable[mpid].pgrp) != 0)
|
|
pgrpInfo[pp-2].pgrpref--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int KERNgetuid(int *ERRNO)
|
|
{
|
|
return (PROC->p_uid);
|
|
/* $$$ return (kp->procTable[Kgetpid()].p_uid); */
|
|
}
|
|
|
|
int KERNgeteuid(int *ERRNO)
|
|
{
|
|
return (PROC->p_euid);
|
|
/* $$$ return (kp->procTable[Kgetpid()].p_euid); */
|
|
}
|
|
|
|
int KERNgetgid(int *ERRNO)
|
|
{
|
|
return (PROC->p_gid);
|
|
/* $$$ return (kp->procTable[Kgetpid()].p_gid); */
|
|
}
|
|
|
|
int KERNgetegid(int *ERRNO)
|
|
{
|
|
return (PROC->p_egid);
|
|
/* $$$ return (kp->procTable[Kgetpid()].p_egid); */
|
|
}
|
|
|
|
int KERNsetreuid(int *ERRNO, int ruid, int euid)
|
|
{
|
|
if (ruid == -1) ruid = PROC->p_uid;
|
|
if (euid == -1) euid = PROC->p_euid;
|
|
if ((PROC->p_uid != 0) &&
|
|
(((euid != PROC->p_uid) && (euid != PROC->p_euid))
|
|
|| ((ruid != PROC->p_euid) && (ruid != PROC->p_uid)))) {
|
|
*ERRNO = EPERM;
|
|
return -1;
|
|
}
|
|
PROC->p_uid = ruid;
|
|
PROC->p_euid = euid;
|
|
return 0;
|
|
}
|
|
|
|
int KERNsetuid(int *ERRNO, int uid)
|
|
{
|
|
/* $$$ struct pentry *p;
|
|
p = &(kp->procTable[Kgetpid()]); */
|
|
|
|
if ((PROC->p_uid == 0) || (uid == PROC->p_uid) || (uid == PROC->p_euid)) {
|
|
PROC->p_uid = uid;
|
|
PROC->p_euid = uid;
|
|
return 0;
|
|
}
|
|
*ERRNO = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
int KERNsetregid(int *ERRNO, int rgid, int egid)
|
|
{
|
|
if (rgid == -1) rgid = PROC->p_gid;
|
|
if (egid == -1) egid = PROC->p_egid;
|
|
if ((PROC->p_uid != 0) &&
|
|
(((egid != PROC->p_gid) && (egid != PROC->p_egid))
|
|
|| ((rgid != PROC->p_egid) && (rgid != PROC->p_gid)))) {
|
|
*ERRNO = EPERM;
|
|
return -1;
|
|
}
|
|
PROC->p_gid = rgid;
|
|
PROC->p_egid = egid;
|
|
return 0;
|
|
}
|
|
|
|
int KERNsetgid(int *ERRNO, int gid)
|
|
{
|
|
/* $$$ struct pentry *p;
|
|
p = &(kp->procTable[Kgetpid()]); */
|
|
|
|
if ((PROC->p_uid == 0) || (gid == PROC->p_gid) || (gid == PROC->p_egid)) {
|
|
PROC->p_gid = gid;
|
|
PROC->p_egid = gid;
|
|
return 0;
|
|
}
|
|
*ERRNO = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
int KERNtimes(int *ERRNO, struct tms *buffer)
|
|
{
|
|
/* $$$ buffer->tms_utime = kp->procTable[Kgetpid()].ticks;
|
|
buffer->tms_cutime = kp->procTable[Kgetpid()].childTicks;
|
|
buffer->tms_stime = buffer->tms_cstime = 0l; */
|
|
|
|
buffer->tms_utime = PROC->ticks;
|
|
buffer->tms_cutime = PROC->childTicks;
|
|
/* a->i1 = a->i2 = b BROKEN in C 2.0.3 */
|
|
#if 0
|
|
buffer->tms_stime = buffer->tms_cstime = 0l;
|
|
#else
|
|
buffer->tms_stime = 0l; buffer->tms_cstime = 0l;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#pragma toolparms 0
|
|
char *a_strncpy_max(char *s, word max_len)
|
|
{
|
|
word l;
|
|
char *x;
|
|
|
|
if (s == NULL) return NULL;
|
|
while ((l < max_len) && (s[l] != 0))
|
|
l++;
|
|
x = malloc(l+1);
|
|
strncpy(x,s,l);
|
|
x[l] = 0;
|
|
return x;
|
|
}
|
|
|
|
int commonFork(void (*funcptr)(), word stackSize, int prio, char *name,
|
|
word *argv, int *ERRNO)
|
|
{
|
|
word dPageAddr, buffSize,nargs;
|
|
int newID,newPID,parentPID;
|
|
int flpid;
|
|
longword *ret;
|
|
handle fstack;
|
|
struct pentry *parent,*child;
|
|
word state;
|
|
byte statereg,slot;
|
|
int i,j,k;
|
|
extern void endproc2(void);
|
|
extern void FORKInitGlob(void);
|
|
extern void IncRefnum(int,int);
|
|
extern void incPipe(int,int);
|
|
extern int allocPID(void);
|
|
|
|
/* printf("address = %08lX\n",subr); */
|
|
if (kp->gsosDebug & 16) fprintf(stderr, "fork(%06lX)\n",funcptr);
|
|
newID = GetNewID(0x1000);
|
|
|
|
fstack = NewHandle((long) stackSize,newID | 0x0100,0xC105, NULL);
|
|
if (toolerror()) { *ERRNO = ENOMEM; return -1; }
|
|
dPageAddr = (word) *fstack;
|
|
buffSize = stackSize;
|
|
|
|
/* calculate the # of bytes of parameters */
|
|
nargs = (*argv) * 2;
|
|
ret = (longword *) (dPageAddr+buffSize-4-nargs);
|
|
/* place this first, or it'll clobber some parameters */
|
|
*ret = ((longword) endproc2)-1; /* go to endproc when process is done */
|
|
|
|
/* if they're passing in params, copy them to the target stack */
|
|
if (nargs)
|
|
memcpy( (((byte *) ret)+3), argv+1, nargs);
|
|
|
|
disableps();
|
|
newPID = createProc(dPageAddr+buffSize-5-nargs,dPageAddr, (longword) funcptr);
|
|
if (newPID == SYSERR) {
|
|
*ERRNO = EAGAIN; DisposeHandle(fstack);
|
|
enableps(); return -1;
|
|
}
|
|
child = &(kp->procTable[newPID]);
|
|
parent = PROC; /* $$$ &(kp->procTable[Kgetpid()]); */
|
|
|
|
child->parentpid = Kgetpid();
|
|
child->irq_A = newID;
|
|
child->irq_X =
|
|
child->irq_Y = 0;
|
|
child->userID = newID;
|
|
if (name != NULL) {
|
|
name = a_strncpy_max(name,128);
|
|
child->args = malloc(strlen(name)+9);
|
|
strcpy(child->args,"BYTEWRKS");
|
|
strcat(child->args,name);
|
|
nfree(name);
|
|
} else child->args = NULL;
|
|
|
|
/* make sure we keep the pgrp refcount up to date */
|
|
child->pgrp = parent->pgrp;
|
|
if (child->pgrp != 0) pgrpInfo[child->pgrp-2].pgrpref++;
|
|
|
|
child->siginfo = malloc(sizeof(struct sigrec));
|
|
memcpy(child->siginfo, parent->siginfo, sizeof(struct sigrec));
|
|
child->waitq = NULL;
|
|
|
|
i = sizeof(fdentry)*(parent->openFiles->fdTableSize-1);
|
|
child->openFiles = malloc(sizeof(fdtable)+i);
|
|
memcpy(child->openFiles, parent->openFiles, sizeof(fdtable)+i);
|
|
|
|
child->prefix = malloc(33*sizeof(GSString255Ptr));
|
|
for (i = 0; i < 33; i++) {
|
|
if (parent->prefix[i] != NULL) {
|
|
child->prefix[i] =
|
|
malloc( ((GSString255Ptr) parent->prefix[i])->length+2 );
|
|
copygsstr(child->prefix[i],parent->prefix[i]);
|
|
} else child->prefix[i] = NULL;
|
|
}
|
|
|
|
child->LInfo = parent->LInfo;
|
|
child->ticks = 0l;
|
|
child->childTicks = 0l;
|
|
child->flags = FL_FORKED | FL_COMPLIANT;
|
|
child->ttyID = parent->ttyID;
|
|
child->executeHook = parent->executeHook;
|
|
child->returnStack = NULL;
|
|
child->p_uid = parent->p_uid;
|
|
child->p_gid = parent->p_gid;
|
|
child->p_euid = parent->p_euid;
|
|
child->p_egid = parent->p_egid;
|
|
child->SANEwap = parent->SANEwap;
|
|
child->lastTool = parent->lastTool; /* actually the resource app number */
|
|
asm {
|
|
lda 0xE0C035
|
|
sta state
|
|
sep #0x30
|
|
lda 0xE0C02D
|
|
sta slot
|
|
lda 0xE0C068
|
|
sta statereg
|
|
rep #0x30
|
|
}
|
|
child->irq_state = state;
|
|
child->irq_SLTROM = slot;
|
|
child->irq_STATEREG = statereg;
|
|
child->alarmCount = 0l;
|
|
child->t2StackPtr = 0;
|
|
child->processState = procNEW; /* brand new! */
|
|
|
|
parentPID = Kgetpid();
|
|
asm {
|
|
ldy newPID
|
|
ldx parentPID
|
|
jsl FORKInitGlob
|
|
}
|
|
|
|
/* make sure the system knows about all of our new copies of those
|
|
file descriptors we inherited */
|
|
|
|
i = child->openFiles->fdCount; k = 0;
|
|
while (i) {
|
|
if (j = child->openFiles->fds[k].refNum) {
|
|
if (child->openFiles->fds[k].refType == rtPIPE)
|
|
incPipe(child->openFiles->fds[k].refFlags,j);
|
|
IncRefnum(child->openFiles->fds[k].refType,j);
|
|
i--;
|
|
}
|
|
k++;
|
|
if (k > child->openFiles->fdTableSize)
|
|
PANIC("BAD FILE DESCRIPTOR TABLE");
|
|
}
|
|
|
|
child->flpid = allocPID();
|
|
kp->numProcs++;
|
|
enableps();
|
|
return child->flpid;
|
|
}
|
|
|
|
#pragma toolparms 1
|
|
|
|
int KERNfork(int *ERRNO,void *subr)
|
|
{
|
|
word nargs = 0;
|
|
|
|
return commonFork((void *)subr, 1024, 0, NULL, &nargs, ERRNO);
|
|
}
|
|
|
|
pascal int KERNfork2(void (*funcptr)(), word stackSize, int prio,
|
|
char *name, word *argv, int *ERRNO)
|
|
{
|
|
return commonFork(funcptr, stackSize, prio, name, argv, ERRNO);
|
|
}
|
|
|
|
|
|
typedef struct GetUserPathRec {
|
|
int pCount;
|
|
int fileSysID;
|
|
int commandNum;
|
|
GSString255Ptr prefixPtr;
|
|
} GetUserPathRec;
|
|
|
|
/*
|
|
* This MUST be in a function by itself so the PROC-> dereference will have
|
|
* an allocated DP to use.
|
|
*/
|
|
static void kill_self(void)
|
|
{
|
|
Kkill(&errno, 9, PROC->flpid);
|
|
}
|
|
|
|
int KERNexecve(int *ERRNO, char *cmdline, char *filename)
|
|
{
|
|
union {
|
|
InitialLoadOutputRec il;
|
|
RestartOutRec r;
|
|
} il_out;
|
|
#define il_rec il_out.il
|
|
#define r_rec il_out.r
|
|
int e;
|
|
word newID;
|
|
GSString255Ptr pfn;
|
|
ResultBuf1KPtr resBuf;
|
|
int ind;
|
|
longword *ret;
|
|
handle fstack;
|
|
int *optionList;
|
|
char **ourPFhand;
|
|
char *args,*argscopy;
|
|
int i,j;
|
|
struct pentry *p;
|
|
ExpandPathRecGS ep;
|
|
PrefixRecGS sp;
|
|
FileInfoRecGS fi;
|
|
int ssf = 0,restart,force_norest = 0;
|
|
word oldUserID, oldFlags, newStack;
|
|
extern ctxt ctxtstuff;
|
|
extern GSString255Ptr __C2GSMALLOC(char *);
|
|
extern void endproc2(void);
|
|
extern void execveHook(void);
|
|
extern void disableBuf(void);
|
|
extern void enableBuf(void);
|
|
|
|
/* always disableps() when screwing with process tables */
|
|
disableps();
|
|
if (kp->gsosDebug & 16) fprintf(stderr,"execve(%s,%s)\n",filename,cmdline);
|
|
|
|
p = PROC; /* $$$ &(kp->procTable[Kgetpid()]);*//* aaaaaaaaaaarrrgghhh!!!!! */
|
|
|
|
/* Don't do anything with the file tables- we simply pass them on to the
|
|
new process */
|
|
|
|
/* turn the input path into a GSString255 */
|
|
pfn = __C2GSMALLOC(filename);
|
|
|
|
/* do an ExpandPath on the input path */
|
|
resBuf = malloc(sizeof(ResultBuf1K));
|
|
ep.pCount = 2;
|
|
ep.inputPath = pfn;
|
|
resBuf->bufSize = 1024;
|
|
ep.outputPath = (ResultBuf255Ptr) resBuf;
|
|
ExpandPathGS(&ep);
|
|
|
|
restart = 1;
|
|
newID = GetUserID2((Pointer)&resBuf->bufString);
|
|
if (toolerror() == 0x1101) {
|
|
/* allocate a new UserID for the program */
|
|
newID = GetNewID(0x1000);
|
|
restart = 0;
|
|
} else {
|
|
/* if the 'newID' is being used by a process, force another copy from disk */
|
|
for (i = 0; i < NPROC; i++) {
|
|
if (kp->procTable[i].processState != procUNUSED)
|
|
if (kp->procTable[i].userID == newID) {
|
|
newID = GetNewID(0x1000);
|
|
restart = 0; force_norest = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (restart) {
|
|
r_rec = Restart(newID);
|
|
} else {
|
|
il_rec = InitialLoad2(newID, (Pointer)&resBuf->bufString, 1, 1);
|
|
}
|
|
if ((e = toolerror())) {
|
|
switch(e) {
|
|
case volNotFound:
|
|
case pathNotFound:
|
|
case fileNotFound:
|
|
*ERRNO = ENOENT;
|
|
break;
|
|
default:
|
|
*ERRNO = EIO;
|
|
break;
|
|
}
|
|
nfree(resBuf);
|
|
enableps();
|
|
return -1;
|
|
}
|
|
|
|
/* get info about the executable so we know how to set up the environment */
|
|
optionList = malloc(48l); /* should be large enough for everything */
|
|
fi.pCount = 8;
|
|
fi.pathname = (GSString255Ptr) &(resBuf->bufString);
|
|
fi.optionList = (void *) optionList;
|
|
optionList[0] = 48;
|
|
GetFileInfoGS(&fi);
|
|
|
|
/* if the executable had no defined stack segment, create 1K by default */
|
|
if (il_rec.buffSize == 0) { /* no stack/dp segment- create one */
|
|
fstack = NewHandle(4096l,newID,0xC015, NULL);
|
|
il_rec.dPageAddr = (word) *fstack;
|
|
il_rec.buffSize = 4096;
|
|
}
|
|
|
|
/* S16s (and others) get no command line arguments, but we should put
|
|
their name in the process table anyway */
|
|
|
|
if (cmdline != NULL) {
|
|
size_t len = strlen(cmdline)+11;
|
|
/* build the command line by tacking the shellid() onto the real
|
|
line */
|
|
args = (char *) malloc(len);
|
|
strcpy(args,"BYTEWRKS");
|
|
strcat(args, cmdline);
|
|
args[((word)(len-1))] = 0; /* Orca 2.0 does this for compat */
|
|
argscopy = pmalloc(len,newID);
|
|
memcpy(argscopy,args,len);
|
|
} else args = argscopy = NULL;
|
|
|
|
/* tricky- shove the address of our generic RTL-exiting shutdown routine
|
|
onto the process stack so we can always keep track of processes */
|
|
ret = (longword *) (il_rec.dPageAddr+il_rec.buffSize-4);
|
|
*ret = ((longword) endproc2)-1; /* go to endproc when process is done */
|
|
|
|
/* set up the registers to point to the command line/shell id combo */
|
|
if (p->args) nfree(p->args); /* free the args string of the old executable */
|
|
p->args = args;
|
|
if (fi.fileType != 0xB5) argscopy = NULL;
|
|
ctxtstuff.ctx_A = newID;
|
|
ctxtstuff.ctx_X = hiWord((longword) argscopy);
|
|
ctxtstuff.ctx_Y = loWord((longword) argscopy);
|
|
newStack = ctxtstuff.ctx_S1 = il_rec.dPageAddr+il_rec.buffSize-5;
|
|
ctxtstuff.ctx_D = il_rec.dPageAddr;
|
|
ctxtstuff.ctx_B = ctxtstuff.ctx_B1 = (((longword) il_rec.startAddr) >> 16);
|
|
ctxtstuff.ctx_PC = (longword) il_rec.startAddr;
|
|
|
|
oldUserID = p->userID;
|
|
oldFlags = p->flags;
|
|
p->userID = newID;
|
|
p->ticks = 0l;
|
|
p->flags = FL_COMPLIANT;
|
|
if (force_norest) p->flags |= FL_NORESTART;
|
|
p->SANEwap = 0; /* reset to the 'not started up' state */
|
|
p->lastTool = 0x401E; /* reset res app to standard */
|
|
|
|
/* is program compliant? */
|
|
if (fi.auxType == 0xDC00l) {
|
|
p->flags &= (~FL_COMPLIANT); /* turn off compliance flag */
|
|
disableBuf(); /* disablebuf now turns off the cursor */
|
|
}
|
|
|
|
/*
|
|
* Set up the prefixes for the new process image
|
|
*/
|
|
|
|
/* modify prefixes 1 and 9 to point to the directory the appl. is in */
|
|
ourPFhand = PROC->prefix; /* $$$ kp->procTable[Kgetpid()].prefix; */
|
|
nfree(ourPFhand[0]); /* the '@' prefix */
|
|
nfree(ourPFhand[1+1]); nfree(ourPFhand[9+1]);
|
|
|
|
/* set Prefixes 1 and 9 to the directory the executable is in */
|
|
for (ind = resBuf->bufString.length-1; ind > 0; ind--)
|
|
if (resBuf->bufString.text[ind] == ':') {
|
|
resBuf->bufString.length = ind+1; break; /* +1 -> snag the colon */
|
|
} /* there will always be one */
|
|
|
|
ourPFhand[9+1] = malloc(resBuf->bufString.length+2);
|
|
copygsstr(ourPFhand[9+1],&resBuf->bufString);
|
|
if (optionList[2] == 0x0D) { /* app is on AppleShare volume - set '@' */
|
|
GetUserPathRec gp;
|
|
gp.pCount = 3; gp.fileSysID = 0x0D; gp.commandNum = 8;
|
|
FSTSpecific(&gp);
|
|
ourPFhand[0] = malloc(gp.prefixPtr->length+3);
|
|
copygsstr(ourPFhand[0],gp.prefixPtr);
|
|
ourPFhand[0][gp.prefixPtr->length+2] = ':';
|
|
((GSString255Ptr)ourPFhand[0])->length++;
|
|
} else {
|
|
ourPFhand[0] = malloc(resBuf->bufString.length+2);
|
|
copygsstr(ourPFhand[0],&resBuf->bufString);
|
|
}
|
|
|
|
/* if prefix 1 would be longer than 64 chars, set it to the NULL prefix */
|
|
if (resBuf->bufString.length > 64) resBuf->bufString.length = 0;
|
|
ourPFhand[2] = malloc(resBuf->bufString.length+2);
|
|
copygsstr(ourPFhand[2],&resBuf->bufString);
|
|
|
|
nfree(pfn);
|
|
nfree(resBuf);
|
|
nfree(optionList);
|
|
|
|
/* If we're launching a S16 application, copy prefix 0 to prefix 8 */
|
|
if (fi.fileType == 0xB3) {
|
|
pfn = (GSString255Ptr) ourPFhand[0+1];
|
|
pfn = malloc(pfn->length+2);
|
|
copygsstr(pfn,ourPFhand[0+1]);
|
|
nfree(ourPFhand[8+1]);
|
|
ourPFhand[8+1] = (char *)pfn;
|
|
}
|
|
|
|
/* Ignored/blocked signals remain ignored/blocked, but caught signals
|
|
are reset to their default state */
|
|
for (i = 0; i < 32; i++) {
|
|
if (p->siginfo->v_signal[i] != SIG_IGN)
|
|
p->siginfo->v_signal[i] = SIG_DFL;
|
|
}
|
|
|
|
SET_STOP_FLAG(&ssf);
|
|
|
|
if (!(oldFlags & FL_COMPLIANT)) {
|
|
enableBuf();
|
|
}
|
|
if ((fi.auxType & 0xDB02) != 0xDB02)
|
|
if (oldFlags & FL_QDSTARTUP) *((byte *)0xE0C029l) &= 0x7F;
|
|
/* switch over to the new stack before we deallocate the one we're using */
|
|
asm {
|
|
lda newStack
|
|
tcs
|
|
}
|
|
if ((fi.auxType == 0xDC00) && (p->ttyID != 3)) {
|
|
fprintf(stderr, "Program can only run on console.\n");
|
|
if (oldFlags & FL_FORKED) {
|
|
DisposeAll(oldUserID); /* process was fork()ed, don't USD */
|
|
DeleteID(oldUserID);
|
|
} else {
|
|
UserShutDown(oldUserID,
|
|
((oldFlags & FL_RESTART) && !(oldFlags & FL_NORESTART)) ? 0x4000 : 0);
|
|
}
|
|
/* don't use any local variables beyond this point */
|
|
/* STACK REPAIR MUST BE OFF TO CALL kill_self() */
|
|
kill_self();
|
|
/* not reached */
|
|
PANIC("EXECVE KILL OVERRUN");
|
|
} else {
|
|
if (oldFlags & FL_FORKED) {
|
|
DisposeAll(oldUserID); /* process was fork()ed, don't USD */
|
|
DeleteID(oldUserID);
|
|
} else {
|
|
UserShutDown(oldUserID,
|
|
((oldFlags & FL_RESTART) && !(oldFlags & FL_NORESTART)) ? 0x4000 : 0);
|
|
}
|
|
/* don't use any local variables beyond this point */
|
|
}
|
|
asm {
|
|
jmp >execveHook
|
|
}
|
|
}
|
|
|
|
/* open the kernel to access the process structures */
|
|
|
|
kvmt *KERNkvm_open(int *ERRNO)
|
|
{
|
|
kvmt *newk;
|
|
|
|
newk = (kvmt *) kmalloc(sizeof(kvmt));
|
|
if (newk == NULL) { *ERRNO = ENOMEM; return NULL;}
|
|
Kkvmsetproc(ERRNO, newk);
|
|
return newk;
|
|
}
|
|
|
|
SYSCALL KERNkvm_close(int *ERRNO,kvmt *k)
|
|
{
|
|
if (kfree(k)) return SYSERR;
|
|
return (OK);
|
|
}
|
|
|
|
struct pentry *KERNkvmgetproc(int *ERRNO, int pid, kvmt *kd)
|
|
{
|
|
int mpid;
|
|
mpid = mapPID(pid);
|
|
if (mpid == -1) { *ERRNO = ESRCH; return NULL; }
|
|
memcpy(&(kd->kvm_pent), &(kp->procTable[mpid]), sizeof(struct pentry));
|
|
kd->pid = pid;
|
|
kd->kvm_pent.parentpid = kp->procTable[kp->procTable[mpid].parentpid].flpid;
|
|
return &(kd->kvm_pent);
|
|
}
|
|
|
|
struct pentry *KERNkvmnextproc(int *ERRNO, kvmt *kd)
|
|
{
|
|
int i;
|
|
int mpid;
|
|
|
|
if (kd->procIndex < NPROC)
|
|
{
|
|
memcpy(&(kd->kvm_pent), &(kp->procTable[kd->procIndex]),
|
|
sizeof(struct pentry));
|
|
kd->pid = kd->kvm_pent.flpid;
|
|
mpid = mapPID(kd->pid);
|
|
kd->kvm_pent.parentpid =
|
|
kp->procTable[kp->procTable[mpid].parentpid].flpid;
|
|
i = kd->procIndex+1;
|
|
while ((i < NPROC) && (kp->procTable[i].processState == procUNUSED))
|
|
i++;
|
|
kd->procIndex = i;
|
|
return &kd->kvm_pent;
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
int KERNkvmsetproc(int *ERRNO,kvmt *kd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NPROC; i++)
|
|
if (kp->procTable[i].processState != procUNUSED) {
|
|
kd->procIndex = i;
|
|
return OK;
|
|
}
|
|
return SYSERR;
|
|
}
|
|
|
|
int KERNtcnewpgrp(int *ERRNO, int fdtty)
|
|
{
|
|
unsigned i,devNum,ttyPgrp;
|
|
fdentryPtr tty;
|
|
extern fdentryPtr getFDptr(int);
|
|
|
|
tty = getFDptr(fdtty);
|
|
if ((tty == NULL) || (tty->refNum == 0)) { *ERRNO = EBADF; return -1; }
|
|
if (tty->refType != rtTTY) { *ERRNO = ENOTTY; return -1; }
|
|
devNum = tty->refNum-1;
|
|
disableps();
|
|
|
|
for (i = 0; i < NPGRP; i++)
|
|
if (!pgrpInfo[i].pgrpref) break;
|
|
|
|
if (i == NPGRP) { enableps(); return -1; }
|
|
|
|
/* we're leaving a PTY, decrement the refcount */
|
|
if (ttyPgrp = ttys[devNum].pgrp)
|
|
pgrpInfo[ttyPgrp-2].pgrpref--;
|
|
if (kp->gsosDebug & 16)
|
|
fprintf(stderr, "tcnewpgrp- TTY:%d pgrp:%d\n",devNum,i+2);
|
|
ttys[devNum].pgrp = i+2;
|
|
pgrpInfo[i].pgrpref++;
|
|
enableps();
|
|
return 0;
|
|
}
|
|
|
|
int KERNsettpgrp(int *ERRNO, int fdtty)
|
|
{
|
|
int p,pid = Kgetpid();
|
|
int pp,devNum;
|
|
fdentryPtr tty;
|
|
extern fdentryPtr getFDptr(int);
|
|
|
|
tty = getFDptr(fdtty);
|
|
if ((tty == NULL) || (tty->refNum == 0)) { *ERRNO = EBADF; return -1; }
|
|
if (tty->refType != rtTTY) { *ERRNO = ENOTTY; return -1; }
|
|
devNum = tty->refNum-1;
|
|
p = ttys[devNum].pgrp;
|
|
if (kp->gsosDebug & 16)
|
|
fprintf(stderr, "settpgrp pid: %d, oldpgrp: %d, ",
|
|
PROC->flpid, PROC->pgrp);
|
|
/* $$$ kp->procTable[pid].flpid,
|
|
kp->procTable[pid].pgrp); */
|
|
|
|
disableps();
|
|
/* $$$ if (kp->procTable[pid].pgrp != p) */
|
|
if (PROC->pgrp != p)
|
|
{
|
|
if (p != 0) pgrpInfo[p-2].pgrpref++;
|
|
/* $$$ if ((pp = kp->procTable[pid].pgrp) != 0) */
|
|
if ((pp = PROC->pgrp) != 0)
|
|
pgrpInfo[pp-2].pgrpref--;
|
|
}
|
|
if (kp->gsosDebug & 16) fprintf(stderr,"newpgrp: %d\n",p);
|
|
/* $$$ kp->procTable[pid].pgrp = p; */
|
|
PROC->pgrp = p;
|
|
enableps();
|
|
}
|
|
|
|
int KERNtctpgrp(int *ERRNO, int pid, int fdtty)
|
|
{
|
|
int p,mpid,devNum;
|
|
fdentryPtr tty;
|
|
extern fdentryPtr getFDptr(int);
|
|
|
|
/* should check pid to be sure it's == getpid or a child of it */
|
|
mpid = mapPID(pid);
|
|
if (mpid == -1) { *ERRNO = ESRCH; return -1; }
|
|
/*
|
|
if (!((mpid == Kgetpid()) || (kp->procTable[mpid].parentpid == Kgetpid())))
|
|
{ *ERRNO = ERANGE; return -1; }
|
|
*/
|
|
tty = getFDptr(fdtty);
|
|
if ((tty == NULL) || (tty->refNum == 0)) { *ERRNO = EBADF; return -1; }
|
|
devNum = tty->refNum-1;
|
|
if (tty->refType != rtTTY) { *ERRNO = ENOTTY; return -1; }
|
|
disableps();
|
|
p = kp->procTable[mpid].pgrp;
|
|
if (p != ttys[devNum].pgrp) {
|
|
if (p != 0) pgrpInfo[p-2].pgrpref++;
|
|
if (ttys[devNum].pgrp != 0)
|
|
pgrpInfo[ttys[devNum].pgrp-2].pgrpref--;
|
|
}
|
|
if (kp->gsosDebug & 16)
|
|
fprintf(stderr,"tctpgrp TTY:%d pid:%d pgrp:%d\n",devNum,pid,p);
|
|
ttys[devNum].pgrp = p;
|
|
enableps();
|
|
}
|
|
|
|
int KERNsetdebug(int code)
|
|
{
|
|
int old;
|
|
|
|
if (kp->gsosDebug & 16) fprintf(stderr,"setdebug %d\n",code);
|
|
if ((code < 0) || (code > 63)) return SYSERR;
|
|
old = kp->gsosDebug;
|
|
kp->gsosDebug = code;
|
|
return old;
|
|
}
|
|
|
|
void *KERNsetsystemvector(void * execvec)
|
|
{
|
|
void *x;
|
|
x = PROC->executeHook;
|
|
PROC->executeHook = execvec;
|
|
|
|
/* $$$ x = kp->procTable[Kgetpid()].executeHook;
|
|
kp->procTable[Kgetpid()].executeHook = execvec; */
|
|
return x;
|
|
}
|
|
|
|
#ifdef NOTDEFINED
|
|
struct pipest {
|
|
handle bufferH; /* the pipe data handle */
|
|
word in; /* write pointer */
|
|
word out; /* read pointer */
|
|
word qflags;
|
|
word RrnCount; /* Why? Because special stuff has to */
|
|
word WrnCount; /* happen in strange conditions */
|
|
|
|
int accessSem;
|
|
int readSem;
|
|
int writeSem;
|
|
int writeStatus;
|
|
}
|
|
#endif
|
|
|
|
/* filedes[0] is read only, filedes[1] is write only */
|
|
int KERNpipe(int *ERRNO, int filedes[2])
|
|
{
|
|
fdentryPtr pread,pwrite;
|
|
int fdread,fdwrite;
|
|
fdtablePtr ft;
|
|
int pipen;
|
|
extern int newPipe(void);
|
|
|
|
if (kp->gsosDebug & 16) printf("pipe(%06lX)\n",filedes);
|
|
/* $$$ ft = kp->procTable[Kgetpid()].openFiles; */
|
|
pipen = newPipe();
|
|
pread = allocFD(&fdread);
|
|
if (pread == NULL) { *ERRNO = EMFILE; disposePipe(pipen); return -1; }
|
|
pwrite = allocFD(&fdwrite);
|
|
ft = PROC->openFiles; /* deref pointer after calls to allocFD */
|
|
if (pwrite == NULL) {
|
|
pread->refNum = 0; /* deallocate the read file descriptor */
|
|
*ERRNO = EMFILE;
|
|
disposePipe(pipen);
|
|
return -1;
|
|
}
|
|
disableps();
|
|
filedes[0] = fdread; filedes[1] = fdwrite;
|
|
/* a->i1 = a->i2 = b BROKEN in C 2.0.3 */
|
|
#if 0
|
|
pread->refNum = pwrite->refNum = pipen;
|
|
pread->refType = pwrite->refType = rtPIPE;
|
|
pread->refLevel = pwrite->refLevel = ft->fdLevel | ft->fdLevelMode;
|
|
pwrite->NLenableMask = pread->NLenableMask = 0;
|
|
#else
|
|
pread->refNum = pipen; pwrite->refNum = pipen;
|
|
pread->refType = rtPIPE; pwrite->refType = rtPIPE;
|
|
pwrite->refLevel = ft->fdLevel | ft->fdLevelMode;
|
|
pread->refLevel = pwrite->refLevel;
|
|
pwrite->NLenableMask = 0; pread->NLenableMask = 0;
|
|
#endif
|
|
pread->refFlags = rfPIPEREAD;
|
|
pwrite->refFlags = rfPIPEWRITE;
|
|
|
|
AddRefnum(rtPIPE,pipen);
|
|
IncRefnum(rtPIPE,pipen);
|
|
ft->fdCount += 2; /* we opened two new files */
|
|
enableps();
|
|
return 0;
|
|
}
|
|
|
|
int KERNdup(int *ERRNO, int filedes)
|
|
{
|
|
/* $$$ struct pentry *p; */
|
|
fdtablePtr ft;
|
|
fdentryPtr newFD,oldFD;
|
|
int nfd;
|
|
int i,j,fd;
|
|
extern void IncRefnum(int,int);
|
|
|
|
disableps();
|
|
/* $$$ p = &(kp->procTable[Kgetpid()]); */
|
|
fd = filedes-1;
|
|
ft = PROC->openFiles;
|
|
if ((filedes < 1) || (filedes > 32) ||
|
|
(ft->fds[fd].refNum == 0)) {
|
|
*ERRNO = EBADF;
|
|
enableps();
|
|
return -1;
|
|
}
|
|
|
|
newFD = allocFD(&nfd);
|
|
ft = PROC->openFiles;
|
|
if (newFD == NULL) { *ERRNO = EMFILE; enableps(); return -1; }
|
|
oldFD = &(ft->fds[fd]);
|
|
memcpy(newFD,oldFD,sizeof(fdentry));
|
|
IncRefnum(newFD->refType,newFD->refNum);
|
|
if (newFD->refType == rtPIPE)
|
|
incPipe(newFD->refFlags,newFD->refNum);
|
|
ft->fdCount++; /* we created a new one... */
|
|
enableps();
|
|
return nfd;
|
|
}
|
|
|
|
int KERNdup2(int *ERRNO, int filedes2, int filedes)
|
|
{
|
|
/* $$$ struct pentry *p; */
|
|
fdtablePtr ft;
|
|
fdentryPtr newFD,oldFD;
|
|
int i,j,fd,fd2;
|
|
extern void IncRefnum(int,int);
|
|
int cl[2];
|
|
|
|
disableps();
|
|
/* $$$ p = &(kp->procTable[Kgetpid()]); */
|
|
ft = PROC->openFiles;
|
|
fd = filedes-1; fd2 = filedes2-1;
|
|
newFD = &(ft->fds[fd2]); oldFD = &(ft->fds[fd]);
|
|
if ((filedes < 1) || (filedes2 < 1) || (filedes > 32) || (filedes2 > 32) ||
|
|
(oldFD->refNum == 0)) {
|
|
*ERRNO = EBADF;
|
|
enableps();
|
|
return -1;
|
|
}
|
|
/* if they're duping a file to itself, pretend we did it */
|
|
if (fd == fd2) {
|
|
enableps(); return 0;
|
|
}
|
|
if (newFD->refNum) {
|
|
cl[0] = 1; cl[1] = filedes2;
|
|
CloseGS(cl);
|
|
}
|
|
memcpy(newFD,oldFD,sizeof(fdentry));
|
|
IncRefnum(newFD->refType,newFD->refNum);
|
|
if (newFD->refType == rtPIPE)
|
|
incPipe(newFD->refFlags,newFD->refNum);
|
|
ft->fdCount++; /* we created a new one... */
|
|
enableps();
|
|
return 0;
|
|
}
|
|
|
|
#pragma databank 0
|
|
#pragma toolparms 0
|
|
|