New interface between PM and FS.

This commit is contained in:
Philip Homburg 2006-05-11 14:57:23 +00:00
parent 94717cb74c
commit 773844a816
28 changed files with 2488 additions and 880 deletions

View file

@ -14,7 +14,7 @@ LDFLAGS = -i
LIBS = -lsys -lsysutil -ltimers
OBJ = main.o open.o read.o write.o pipe.o dmap.o \
device.o path.o mount.o link.o super.o inode.o \
device.o exec.o path.o mount.o link.o super.o inode.o \
cache.o cache2.o filedes.o stadir.o protect.o time.o \
lock.o misc.o utility.o select.o timers.o table.o

View file

@ -58,6 +58,7 @@ int only_search; /* if NO_READ, don't read, else act normal */
if (dev != NO_DEV) {
b = (int) block & HASH_MASK;
bp = buf_hash[b];
while (bp != NIL_BUF) {
if (bp->b_blocknr == block && bp->b_dev == dev) {
/* Block needed has been found. */
@ -84,12 +85,14 @@ int only_search; /* if NO_READ, don't read, else act normal */
} else {
/* The block just taken is not on the front of its hash chain. */
while (prev_ptr->b_hash != NIL_BUF)
{
if (prev_ptr->b_hash == bp) {
prev_ptr->b_hash = bp->b_hash; /* found it */
break;
} else {
prev_ptr = prev_ptr->b_hash; /* keep looking */
}
}
}
/* If the block taken is dirty, make it clean by writing it to the disk.
@ -269,7 +272,7 @@ int rw_flag; /* READING or WRITING */
if ( (dev = bp->b_dev) != NO_DEV) {
pos = (off_t) bp->b_blocknr * block_size;
op = (rw_flag == READING ? DEV_READ : DEV_WRITE);
r = dev_io(op, dev, FS_PROC_NR, bp->b_data, pos, block_size, 0);
r = dev_bio(op, dev, FS_PROC_NR, bp->b_data, pos, block_size, 0);
if (r != block_size) {
if (r >= 0) r = END_OF_FILE;
if (r != END_OF_FILE)
@ -371,7 +374,7 @@ int rw_flag; /* READING or WRITING */
iop->iov_addr = (vir_bytes) bp->b_data;
iop->iov_size = block_size;
}
r = dev_io(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER,
r = dev_bio(rw_flag == WRITING ? DEV_SCATTER : DEV_GATHER,
dev, FS_PROC_NR, iovec,
(off_t) bufq[0]->b_blocknr * block_size, j, 0);
@ -433,12 +436,123 @@ struct buf *bp;
next_ptr = bp->b_next; /* successor on LRU chain */
prev_ptr = bp->b_prev; /* predecessor on LRU chain */
if (prev_ptr != NIL_BUF)
{
prev_ptr->b_next = next_ptr;
}
else
front = next_ptr; /* this block was at front of chain */
if (next_ptr != NIL_BUF)
{
next_ptr->b_prev = prev_ptr;
}
else
rear = prev_ptr; /* this block was at rear of chain */
}
#if 0
PRIVATE void check_lru()
{
int i;
struct buf *bp, *nbp;
for (i= 0; i<NR_BUFS; i++)
{
bp= &buf[i];
nbp= bp->b_next;
if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS]))
{
stacktrace();
panic(__FILE__, "check_lru: bad next", nbp);
}
nbp= bp->b_prev;
if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS]))
{
stacktrace();
panic(__FILE__, "check_lru: bad next", nbp);
}
}
}
PRIVATE void check_buf(bp)
struct buf *bp;
{
struct buf *nbp;
if (bp < buf || bp >= &buf[NR_BUFS])
{
stacktrace();
panic(__FILE__, "check_buf: bad buf", bp);
}
nbp= bp->b_next;
if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS]))
{
stacktrace();
panic(__FILE__, "check_buf: bad next", nbp);
}
nbp= bp->b_prev;
if (nbp != NULL && (nbp < buf || nbp >= &buf[NR_BUFS]))
{
stacktrace();
panic(__FILE__, "check_buf: bad next", nbp);
}
}
PRIVATE void check_hash_chains()
{
int i;
struct buf *bp;
for (i= 0; i<NR_BUFS; i++)
{
bp= &buf[i];
while (bp)
{
if (bp < buf || bp >= &buf[NR_BUFS])
{
panic(__FILE__, "check_hash_chains: bad buf",
bp);
}
bp= bp->b_hash;
}
}
}
PUBLIC void check_hash_chainsX(file, line)
char *file;
int line;
{
int i;
struct buf *bp;
for (i= 0; i<NR_BUF_HASH; i++)
{
bp= buf_hash[i];
while (bp)
{
if (bp < buf || bp >= &buf[NR_BUFS])
{
printf(
"check_hash_chainsX: called from %s, %d\n",
file, line);
panic(__FILE__, "check_hash_chainsX: bad buf",
bp);
}
bp= bp->b_hash;
}
}
}
PRIVATE void check_hash_chain(bp)
struct buf *bp;
{
while (bp)
{
if (bp < buf || bp >= &buf[NR_BUFS])
{
panic(__FILE__, "check_hash_chain: bad buf", bp);
}
bp= bp->b_hash;
}
}
#endif

View file

@ -14,7 +14,7 @@
* ctty_opcl: perform controlling-tty-specific processing for open/close
* ctty_io: perform controlling-tty-specific processing for I/O
* do_ioctl: perform the IOCTL system call
* do_setsid: perform the SETSID system call (FS side)
* pm_setsid: perform the SETSID system call (FS side)
*/
#include "fs.h"
@ -117,6 +117,91 @@ PUBLIC void dev_status(message *m)
return;
}
/*===========================================================================*
* dev_bio *
*===========================================================================*/
PUBLIC int dev_bio(op, dev, proc_e, buf, pos, bytes, flags)
int op; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
dev_t dev; /* major-minor device number */
int proc_e; /* in whose address space is buf? */
void *buf; /* virtual address of the buffer */
off_t pos; /* byte position */
int bytes; /* how many bytes to transfer */
int flags; /* special flags, like O_NONBLOCK */
{
/* Read or write from a device. The parameter 'dev' tells which one. */
struct dmap *dp;
int r;
message m;
/* Determine task dmap. */
dp = &dmap[(dev >> MAJOR) & BYTE];
for (;;)
{
/* See if driver is roughly valid. */
if (dp->dmap_driver == NONE) {
printf("FS: dev_io: no driver for dev %x\n", dev);
return ENXIO;
}
/* Set up the message passed to task. */
m.m_type = op;
m.DEVICE = (dev >> MINOR) & BYTE;
m.POSITION = pos;
m.IO_ENDPT = proc_e;
m.ADDRESS = buf;
m.COUNT = bytes;
m.TTY_FLAGS = flags;
/* Call the task. */
(*dp->dmap_io)(dp->dmap_driver, &m);
if(dp->dmap_driver == NONE) {
/* Driver has vanished. Wait for a new one. */
for (;;)
{
r= receive(RS_PROC_NR, &m);
if (r != OK)
{
panic(__FILE__,
"dev_bio: unable to receive from RS",
r);
}
if (m.m_type == DEVCTL)
{
r= fs_devctl(m.ctl_req, m.dev_nr, m.driver_nr,
m.dev_style, m.m_force);
}
else
{
panic(__FILE__,
"dev_bio: got message from RS, type",
m.m_type);
}
m.m_type= r;
r= send(RS_PROC_NR, &m);
if (r != OK)
{
panic(__FILE__,
"dev_bio: unable to send to RS",
r);
}
if (dp->dmap_driver != NONE)
break;
}
printf("dev_bio: trying new driver\n");
continue;
}
/* Task has completed. See if call completed. */
if (m.REP_STATUS == SUSPEND) {
panic(__FILE__, "dev_bio: driver returned SUSPEND", NO_NUM);
}
return(m.REP_STATUS);
}
}
/*===========================================================================*
* dev_io *
*===========================================================================*/
@ -208,11 +293,6 @@ int flags; /* mode bits and flags */
printf("FS: gen_opcl: no driver for dev %x\n", dev);
return ENXIO;
}
if(isokendpt(dp->dmap_driver, &dummyproc) != OK) {
printf("FS: gen_opcl: old driver for dev %x (%d)\n",
dev, dp->dmap_driver);
return ENXIO;
}
/* Call the task. */
(*dp->dmap_io)(dp->dmap_driver, &dev_mess);
@ -274,9 +354,10 @@ int flags; /* mode bits and flags */
}
/*===========================================================================*
* do_setsid *
* pm_setsid *
*===========================================================================*/
PUBLIC int do_setsid()
PUBLIC void pm_setsid(proc_e)
int proc_e;
{
/* Perform the FS side of the SETSID call, i.e. get rid of the controlling
* terminal of a process, and make the process a session leader.
@ -284,15 +365,11 @@ PUBLIC int do_setsid()
register struct fproc *rfp;
int slot;
/* Only MM may do the SETSID call directly. */
if (who_e != PM_PROC_NR) return(ENOSYS);
/* Make the process a session leader with no controlling tty. */
okendpt(m_in.endpt1, &slot);
okendpt(proc_e, &slot);
rfp = &fproc[slot];
rfp->fp_sesldr = TRUE;
rfp->fp_tty = 0;
return(OK);
}
/*===========================================================================*

View file

@ -60,31 +60,47 @@ PRIVATE struct dmap init_dmap[] = {
*===========================================================================*/
PUBLIC int do_devctl()
{
int result, proc_nr_e, proc_nr_n;
return fs_devctl(m_in.ctl_req, m_in.dev_nr, m_in.driver_nr,
m_in.dev_style, m_in.m_force);
}
switch(m_in.ctl_req) {
/*===========================================================================*
* fs_devctl *
*===========================================================================*/
PUBLIC int fs_devctl(req, dev, proc_nr_e, style, force)
int req;
int dev;
int proc_nr_e;
int style;
int force;
{
int result, proc_nr_n;
switch(req) {
case DEV_MAP:
/* Check process number of new driver. */
proc_nr_e= m_in.driver_nr;
if (isokendpt(proc_nr_e, &proc_nr_n) != OK)
return(EINVAL);
if (!force)
{
/* Check process number of new driver. */
if (isokendpt(proc_nr_e, &proc_nr_n) != OK)
return(EINVAL);
}
/* Try to update device mapping. */
result = map_driver(m_in.dev_nr, proc_nr_e, m_in.dev_style);
result = map_driver(dev, proc_nr_e, style, force);
if (result == OK)
{
/* If a driver has completed its exec(), it can be announced to be
* up.
*/
if(fproc[proc_nr_n].fp_execced) {
dev_up(m_in.dev_nr);
if(force || fproc[proc_nr_n].fp_execced) {
dev_up(dev);
} else {
dmap[m_in.dev_nr].dmap_flags |= DMAP_BABY;
dmap[dev].dmap_flags |= DMAP_BABY;
}
}
break;
case DEV_UNMAP:
result = map_driver(m_in.dev_nr, NONE, 0);
result = map_driver(dev, NONE, 0, 0);
break;
default:
result = EINVAL;
@ -95,10 +111,11 @@ PUBLIC int do_devctl()
/*===========================================================================*
* map_driver *
*===========================================================================*/
PUBLIC int map_driver(major, proc_nr_e, style)
PUBLIC int map_driver(major, proc_nr_e, style, force)
int major; /* major number of the device */
int proc_nr_e; /* process number of the driver */
int style; /* style of the device */
int force;
{
/* Set a new device driver mapping in the dmap table. Given that correct
* arguments are given, this only works if the entry is mutable and the
@ -131,9 +148,12 @@ int style; /* style of the device */
if (! (dp->dmap_flags & DMAP_MUTABLE)) return(EPERM);
if (dp->dmap_flags & DMAP_BUSY) return(EBUSY);
/* Check process number of new driver. */
if (isokendpt(proc_nr_e, &proc_nr_n) != OK)
return(EINVAL);
if (!force)
{
/* Check process number of new driver. */
if (isokendpt(proc_nr_e, &proc_nr_n) != OK)
return(EINVAL);
}
/* Try to update the entry. */
switch (style) {
@ -156,7 +176,7 @@ PUBLIC void dmap_unmap_by_endpt(int proc_nr_e)
int i, r;
for (i=0; i<NR_DEVICES; i++)
if(dmap[i].dmap_driver && dmap[i].dmap_driver == proc_nr_e)
if((r=map_driver(i, NONE, 0)) != OK)
if((r=map_driver(i, NONE, 0, 0)) != OK)
printf("FS: unmap of p %d / d %d failed: %d\n", proc_nr_e,i,r);
return;

622
servers/fs/exec.c Normal file
View file

@ -0,0 +1,622 @@
/* This file handles the EXEC system call. It performs the work as follows:
* - see if the permissions allow the file to be executed
* - read the header and extract the sizes
* - fetch the initial args and environment from the user space
* - allocate the memory for the new process
* - copy the initial stack from PM to the process
* - read in the text and data segments and copy to the process
* - take care of setuid and setgid bits
* - fix up 'mproc' table
* - tell kernel about EXEC
* - save offset to initial argc (for ps)
*
* The entry points into this file are:
* pm_exec: perform the EXEC system call
*/
#include "fs.h"
#include <sys/stat.h>
#include <minix/callnr.h>
#include <minix/endpoint.h>
#include <minix/com.h>
#include <a.out.h>
#include <signal.h>
#include <string.h>
#include "buf.h"
#include "fproc.h"
#include "inode.h"
#include "param.h"
#include "super.h"
FORWARD _PROTOTYPE( int exec_newmem, (int proc_e, vir_bytes text_bytes,
vir_bytes data_bytes, vir_bytes bss_bytes, vir_bytes tot_bytes,
vir_bytes frame_len, int sep_id,
Dev_t st_dev, ino_t st_ino, time_t st_ctime, char *progname,
int new_uid, int new_gid,
vir_bytes *stack_topp, int *load_textp, int *allow_setuidp) );
FORWARD _PROTOTYPE( int read_header, (struct inode *rip, int *sep_id,
vir_bytes *text_bytes, vir_bytes *data_bytes,
vir_bytes *bss_bytes, phys_bytes *tot_bytes, vir_bytes *pc,
int *hdrlenp) );
FORWARD _PROTOTYPE( int patch_stack, (struct inode *rip,
char stack[ARG_MAX], vir_bytes *stk_bytes) );
FORWARD _PROTOTYPE( int insert_arg, (char stack[ARG_MAX],
vir_bytes *stk_bytes, char *arg, int replace) );
FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX],
vir_bytes base) );
FORWARD _PROTOTYPE( int read_seg, (struct inode *rip, off_t off,
int proc_e, int seg, phys_bytes seg_bytes) );
FORWARD _PROTOTYPE( void clo_exec, (struct fproc *rfp) );
#define ESCRIPT (-2000) /* Returned by read_header for a #! script. */
#define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
/*===========================================================================*
* pm_exec *
*===========================================================================*/
PUBLIC int pm_exec(proc_e, path, path_len, frame, frame_len)
int proc_e;
char *path;
vir_bytes path_len;
char *frame;
vir_bytes frame_len;
{
/* Perform the execve(name, argv, envp) call. The user library builds a
* complete stack image, including pointers, args, environ, etc. The stack
* is copied to a buffer inside FS, and then to the new core image.
*/
int r, sep_id, round, proc_s, hdrlen, load_text, allow_setuid;
vir_bytes text_bytes, data_bytes, bss_bytes, pc;
phys_bytes tot_bytes; /* total space for program, including gap */
vir_bytes stack_top, vsp;
off_t off;
uid_t new_uid;
gid_t new_gid;
struct fproc *rfp;
struct inode *rip;
char *cp;
char progname[PROC_NAME_LEN];
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
okendpt(proc_e, &proc_s);
rfp= fp= &fproc[proc_s];
who_e= proc_e;
who_p= proc_s;
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
/* Get the exec file name. */
r= fetch_name(path, path_len, 0);
if (r != OK)
{
printf("pm_exec: fetch_name failed\n");
return(r); /* file name not in user data segment */
}
/* Fetch the stack from the user before destroying the old core image. */
if (frame_len > ARG_MAX)
{
printf("pm_exec: bad frame_len\n");
return(ENOMEM); /* stack too big */
}
r = sys_datacopy(proc_e, (vir_bytes) frame,
SELF, (vir_bytes) mbuf, (phys_bytes)frame_len);
/* can't fetch stack (e.g. bad virtual addr) */
if (r != OK)
{
printf("pm_exec: sys_datacopy failed\n");
return(r);
}
/* The default is the keep the original user and group IDs */
new_uid= rfp->fp_effuid;
new_gid= rfp->fp_effgid;
for (round= 0; round < 2; round++)
/* round = 0 (first attempt), or 1 (interpreted script) */
{
/* Save the name of the program */
(cp= strrchr(user_path, '/')) ? cp++ : (cp= user_path);
strncpy(progname, cp, PROC_NAME_LEN-1);
progname[PROC_NAME_LEN-1] = '\0';
#if 0
printf("pm_exec: eat_path '%s'\n", user_path);
#endif
rip= eat_path(user_path);
if (rip == NIL_INODE)
{
return(err_code);
}
if ((rip->i_mode & I_TYPE) != I_REGULAR)
r = ENOEXEC;
else
r = forbidden(rip, X_BIT); /* check if file is executable */
if (r != OK) {
put_inode(rip);
printf("pm_exec: bad executable\n");
return(r);
}
if (round == 0)
{
/* Deal with setuid/setgid executables */
if (rip->i_mode & I_SET_UID_BIT)
new_uid = rip->i_uid;
if (rip->i_mode & I_SET_GID_BIT)
new_gid = rip->i_gid;
}
/* Read the file header and extract the segment sizes. */
r = read_header(rip, &sep_id, &text_bytes, &data_bytes, &bss_bytes,
&tot_bytes, &pc, &hdrlen);
if (r != ESCRIPT || round != 0)
break;
/* Get fresh copy of the file name. */
r= fetch_name(path, path_len, 0);
if (r != OK)
{
printf("pm_exec: 2nd fetch_name failed\n");
put_inode(rip);
return(r); /* strange */
}
r= patch_stack(rip, mbuf, &frame_len);
put_inode(rip);
if (r != OK)
{
printf("pm_exec: patch stack\n");
return r;
}
}
if (r != OK)
{
printf("pm_exec: returning ENOEXEC, r = %d\n", r);
return ENOEXEC;
}
r= exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes,
frame_len, sep_id, rip->i_dev, rip->i_num, rip->i_ctime,
progname, new_uid, new_gid, &stack_top, &load_text, &allow_setuid);
if (r != OK)
{
printf("pm_exec: exec_newmap failed: %d\n", r);
put_inode(rip);
return r;
}
/* Patch up stack and copy it from FS to new core image. */
vsp = stack_top;
vsp -= frame_len;
patch_ptr(mbuf, vsp);
r = sys_datacopy(SELF, (vir_bytes) mbuf,
proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
if (r != OK) panic(__FILE__,"pm_exec stack copy err on", proc_e);
off = hdrlen;
/* Read in text and data segments. */
if (load_text) {
r= read_seg(rip, off, proc_e, T, text_bytes);
}
off += text_bytes;
if (r == OK)
r= read_seg(rip, off, proc_e, D, data_bytes);
put_inode(rip);
if (r != OK) return r;
clo_exec(rfp);
if (allow_setuid)
{
rfp->fp_effuid= new_uid;
rfp->fp_effgid= new_gid;
}
/* This child has now exec()ced. */
rfp->fp_execced = 1;
/* Check if this is a driver that can now be useful. */
dmap_endpt_up(rfp->fp_endpoint);
return OK;
}
/*===========================================================================*
* exec_newmem *
*===========================================================================*/
PRIVATE int exec_newmem(proc_e, text_bytes, data_bytes, bss_bytes, tot_bytes,
frame_len, sep_id, st_dev, st_ino, st_ctime, progname,
new_uid, new_gid, stack_topp, load_textp, allow_setuidp)
int proc_e;
vir_bytes text_bytes;
vir_bytes data_bytes;
vir_bytes bss_bytes;
vir_bytes tot_bytes;
vir_bytes frame_len;
int sep_id;
dev_t st_dev;
ino_t st_ino;
time_t st_ctime;
int new_uid;
int new_gid;
char *progname;
vir_bytes *stack_topp;
int *load_textp;
int *allow_setuidp;
{
int r;
struct exec_newmem e;
message m;
e.text_bytes= text_bytes;
e.data_bytes= data_bytes;
e.bss_bytes= bss_bytes;
e.tot_bytes= tot_bytes;
e.args_bytes= frame_len;
e.sep_id= sep_id;
e.st_dev= st_dev;
e.st_ino= st_ino;
e.st_ctime= st_ctime;
e.new_uid= new_uid;
e.new_gid= new_gid;
strncpy(e.progname, progname, sizeof(e.progname)-1);
e.progname[sizeof(e.progname)-1]= '\0';
m.m_type= EXEC_NEWMEM;
m.EXC_NM_PROC= proc_e;
m.EXC_NM_PTR= (char *)&e;
r= sendrec(PM_PROC_NR, &m);
if (r != OK)
return r;
#if 0
printf("exec_newmem: r = %d, m_type = %d\n", r, m.m_type);
#endif
*stack_topp= m.m1_i1;
*load_textp= !!(m.m1_i2 & EXC_NM_RF_LOAD_TEXT);
*allow_setuidp= !!(m.m1_i2 & EXC_NM_RF_ALLOW_SETUID);
#if 0
printf("exec_newmem: stack_top = 0x%x\n", *stack_topp);
printf("exec_newmem: load_text = %d\n", *load_textp);
#endif
return m.m_type;
}
/*===========================================================================*
* read_header *
*===========================================================================*/
PRIVATE int read_header(rip, sep_id, text_bytes, data_bytes, bss_bytes,
tot_bytes, pc, hdrlenp)
struct inode *rip; /* inode for reading exec file */
int *sep_id; /* true iff sep I&D */
vir_bytes *text_bytes; /* place to return text size */
vir_bytes *data_bytes; /* place to return initialized data size */
vir_bytes *bss_bytes; /* place to return bss size */
phys_bytes *tot_bytes; /* place to return total size */
vir_bytes *pc; /* program entry point (initial PC) */
int *hdrlenp;
{
/* Read the header and extract the text, data, bss and total sizes from it. */
off_t pos;
block_t b;
struct buf *bp;
struct exec hdr; /* a.out header is read in here */
/* Read the header and check the magic number. The standard MINIX header
* is defined in <a.out.h>. It consists of 8 chars followed by 6 longs.
* Then come 4 more longs that are not used here.
* Byte 0: magic number 0x01
* Byte 1: magic number 0x03
* Byte 2: normal = 0x10 (not checked, 0 is OK), separate I/D = 0x20
* Byte 3: CPU type, Intel 16 bit = 0x04, Intel 32 bit = 0x10,
* Motorola = 0x0B, Sun SPARC = 0x17
* Byte 4: Header length = 0x20
* Bytes 5-7 are not used.
*
* Now come the 6 longs
* Bytes 8-11: size of text segments in bytes
* Bytes 12-15: size of initialized data segment in bytes
* Bytes 16-19: size of bss in bytes
* Bytes 20-23: program entry point
* Bytes 24-27: total memory allocated to program (text, data + stack)
* Bytes 28-31: size of symbol table in bytes
* The longs are represented in a machine dependent order,
* little-endian on the 8088, big-endian on the 68000.
* The header is followed directly by the text and data segments, and the
* symbol table (if any). The sizes are given in the header. Only the
* text and data segments are copied into memory by exec. The header is
* used here only. The symbol table is for the benefit of a debugger and
* is ignored here.
*/
pos= 0; /* Read from the start of the file */
b = read_map(rip, pos); /* get block number */
if (b == 0) /* Hole */
return ENOEXEC;
bp = get_block(rip->i_dev, b, NORMAL); /* get block */
/* Interpreted script? */
if (bp->b_data[0] == '#' && bp->b_data[1] == '!' && rip->i_size >= 2)
{
put_block(bp, FULL_DATA_BLOCK);
return ESCRIPT;
}
memcpy(&hdr, bp->b_data, sizeof(hdr));
put_block(bp, FULL_DATA_BLOCK);
if (rip->i_size < A_MINHDR) return(ENOEXEC);
/* Check magic number, cpu type, and flags. */
if (BADMAG(hdr)) return(ENOEXEC);
#if (CHIP == INTEL && _WORD_SIZE == 2)
if (hdr.a_cpu != A_I8086) return(ENOEXEC);
#endif
#if (CHIP == INTEL && _WORD_SIZE == 4)
if (hdr.a_cpu != A_I80386) return(ENOEXEC);
#endif
if ((hdr.a_flags & ~(A_NSYM | A_EXEC | A_SEP)) != 0) return(ENOEXEC);
*sep_id = !!(hdr.a_flags & A_SEP); /* separate I & D or not */
/* Get text and data sizes. */
*text_bytes = (vir_bytes) hdr.a_text; /* text size in bytes */
*data_bytes = (vir_bytes) hdr.a_data; /* data size in bytes */
*bss_bytes = (vir_bytes) hdr.a_bss; /* bss size in bytes */
*tot_bytes = hdr.a_total; /* total bytes to allocate for prog */
if (*tot_bytes == 0) return(ENOEXEC);
if (!*sep_id) {
/* If I & D space is not separated, it is all considered data. Text=0*/
*data_bytes += *text_bytes;
*text_bytes = 0;
}
*pc = hdr.a_entry; /* initial address to start execution */
*hdrlenp = hdr.a_hdrlen & BYTE; /* header length */
return(OK);
}
/*===========================================================================*
* patch_stack *
*===========================================================================*/
PRIVATE int patch_stack(rip, stack, stk_bytes)
struct inode *rip; /* pointer for open script file */
char stack[ARG_MAX]; /* pointer to stack image within FS */
vir_bytes *stk_bytes; /* size of initial stack */
{
/* Patch the argument vector to include the path name of the script to be
* interpreted, and all strings on the #! line. Returns the path name of
* the interpreter.
*/
enum { INSERT=FALSE, REPLACE=TRUE };
int n;
off_t pos;
block_t b;
struct buf *bp;
char *sp, *interp = NULL;
/* Make user_path the new argv[0]. */
if (!insert_arg(stack, stk_bytes, user_path, REPLACE)) return(ENOMEM);
pos= 0; /* Read from the start of the file */
b = read_map(rip, pos); /* get block number */
if (b == 0) /* Hole */
return ENOEXEC;
bp = get_block(rip->i_dev, b, NORMAL); /* get block */
n= rip->i_size;
if (n > rip->i_sp->s_block_size)
n= rip->i_sp->s_block_size;
if (n < 2)
{
put_block(bp, FULL_DATA_BLOCK);
return ENOEXEC;
}
sp= bp->b_data+2; /* just behind the #! */
n -= 2;
if (n > PATH_MAX)
n= PATH_MAX;
/* Use the user_path variable for temporary storage */
memcpy(user_path, sp, n);
put_block(bp, FULL_DATA_BLOCK);
if ((sp= memchr(user_path, '\n', n)) == NULL) /* must be a proper line */
return(ENOEXEC);
/* Move sp backwards through script[], prepending each string to stack. */
for (;;) {
/* skip spaces behind argument. */
while (sp > user_path && (*--sp == ' ' || *sp == '\t')) {}
if (sp == user_path) break;
sp[1] = 0;
/* Move to the start of the argument. */
while (sp > user_path && sp[-1] != ' ' && sp[-1] != '\t') --sp;
interp = sp;
if (!insert_arg(stack, stk_bytes, sp, INSERT)) return(ENOMEM);
}
/* Round *stk_bytes up to the size of a pointer for alignment contraints. */
*stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE;
if (interp != user_path)
memmove(user_path, interp, strlen(interp)+1);
return(OK);
}
/*===========================================================================*
* insert_arg *
*===========================================================================*/
PRIVATE int insert_arg(stack, stk_bytes, arg, replace)
char stack[ARG_MAX]; /* pointer to stack image within PM */
vir_bytes *stk_bytes; /* size of initial stack */
char *arg; /* argument to prepend/replace as new argv[0] */
int replace;
{
/* Patch the stack so that arg will become argv[0]. Be careful, the stack may
* be filled with garbage, although it normally looks like this:
* nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
* followed by the strings "pointed" to by the argv[i] and the envp[i]. The
* pointers are really offsets from the start of stack.
* Return true iff the operation succeeded.
*/
int offset, a0, a1, old_bytes = *stk_bytes;
/* Prepending arg adds at least one string and a zero byte. */
offset = strlen(arg) + 1;
a0 = (int) ((char **) stack)[1]; /* argv[0] */
if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE);
a1 = a0; /* a1 will point to the strings to be moved */
if (replace) {
/* Move a1 to the end of argv[0][] (argv[1] if nargs > 1). */
do {
if (a1 == old_bytes) return(FALSE);
--offset;
} while (stack[a1++] != 0);
} else {
offset += PTRSIZE; /* new argv[0] needs new pointer in argv[] */
a0 += PTRSIZE; /* location of new argv[0][]. */
}
/* stack will grow by offset bytes (or shrink by -offset bytes) */
if ((*stk_bytes += offset) > ARG_MAX) return(FALSE);
/* Reposition the strings by offset bytes */
memmove(stack + a1 + offset, stack + a1, old_bytes - a1);
strcpy(stack + a0, arg); /* Put arg in the new space. */
if (!replace) {
/* Make space for a new argv[0]. */
memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE);
((char **) stack)[0]++; /* nargs++; */
}
/* Now patch up argv[] and envp[] by offset. */
patch_ptr(stack, (vir_bytes) offset);
((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */
return(TRUE);
}
/*===========================================================================*
* patch_ptr *
*===========================================================================*/
PRIVATE void patch_ptr(stack, base)
char stack[ARG_MAX]; /* pointer to stack image within PM */
vir_bytes base; /* virtual address of stack base inside user */
{
/* When doing an exec(name, argv, envp) call, the user builds up a stack
* image with arg and env pointers relative to the start of the stack. Now
* these pointers must be relocated, since the stack is not positioned at
* address 0 in the user's address space.
*/
char **ap, flag;
vir_bytes v;
flag = 0; /* counts number of 0-pointers seen */
ap = (char **) stack; /* points initially to 'nargs' */
ap++; /* now points to argv[0] */
while (flag < 2) {
if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
if (*ap != NULL) {
v = (vir_bytes) *ap; /* v is relative pointer */
v += base; /* relocate it */
*ap = (char *) v; /* put it back */
} else {
flag++;
}
ap++;
}
}
/*===========================================================================*
* read_seg *
*===========================================================================*/
PRIVATE int read_seg(rip, off, proc_e, seg, seg_bytes)
struct inode *rip; /* inode descriptor to read from */
off_t off; /* offset in file */
int proc_e; /* process number (endpoint) */
int seg; /* T, D, or S */
phys_bytes seg_bytes; /* how much is to be transferred? */
{
/*
* The byte count on read is usually smaller than the segment count, because
* a segment is padded out to a click multiple, and the data segment is only
* partially initialized.
*/
int r, block_size;
off_t n, o, b_off, seg_off;
block_t b;
struct buf *bp;
/* Make sure that the file is big enough */
if (rip->i_size < off+seg_bytes)
return EIO;
block_size= rip->i_sp->s_block_size;
seg_off= 0;
for (o= off - (off % block_size); o < off+seg_bytes; o += block_size)
{
b= read_map(rip, o);
if (b == NO_BLOCK)
return EIO; /* Executables don't have holes */
bp = get_block(rip->i_dev, b, NORMAL); /* get block */
if (o < off)
b_off= off-o;
else
b_off= 0;
n= block_size-b_off;
if (o+b_off+n > off+seg_bytes)
n= off+seg_bytes-(o+b_off);
r= sys_vircopy(SELF, D, (vir_bytes)bp->b_data+b_off,
proc_e, seg, seg_off, n);
put_block(bp, FULL_DATA_BLOCK);
if (r != OK)
return r;
seg_off += n;
}
return OK;
}
/*===========================================================================*
* clo_exec *
*===========================================================================*/
PRIVATE void clo_exec(rfp)
struct fproc *rfp;
{
/* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec).
*/
int i, proc;
long bitmap;
/* The array of FD_CLOEXEC bits is in the fp_cloexec bit map. */
bitmap = rfp->fp_cloexec;
if (bitmap) {
/* Check the file desriptors one by one for presence of FD_CLOEXEC. */
for (i = 0; i < OPEN_MAX; i++) {
if ( (bitmap >> i) & 01) (void) close_fd(rfp, i);
}
}
}

View file

@ -66,11 +66,23 @@ PUBLIC int get_fd(int start, mode_t bits, int *k, struct filp **fpt)
PUBLIC struct filp *get_filp(fild)
int fild; /* file descriptor */
{
/* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */
return get_filp2(fp, fild);
}
/*===========================================================================*
* get_filp2 *
*===========================================================================*/
PUBLIC struct filp *get_filp2(rfp, fild)
register struct fproc *rfp;
int fild; /* file descriptor */
{
/* See if 'fild' refers to a valid file descr. If so, return its filp ptr. */
err_code = EBADF;
if (fild < 0 || fild >= OPEN_MAX ) return(NIL_FILP);
return(fp->fp_filp[fild]); /* may also be NIL_FILP */
return(rfp->fp_filp[fild]); /* may also be NIL_FILP */
}
/*===========================================================================*

View file

@ -34,6 +34,7 @@ struct super_block; /* proto.h needs to know this */
FORWARD _PROTOTYPE( void fs_init, (void) );
FORWARD _PROTOTYPE( void get_work, (void) );
FORWARD _PROTOTYPE( void init_root, (void) );
FORWARD _PROTOTYPE( void service_pm, (void) );
/*===========================================================================*
* main *
@ -48,23 +49,25 @@ PUBLIC int main()
fs_init();
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
get_work(); /* sets who and call_nr */
fp = &fproc[who_p]; /* pointer to proc table struct */
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
if (who_e == PM_PROC_NR && call_nr != PROC_EVENT)
printf("FS: strange, got message %d from PM\n", call_nr);
/* Check for special control messages first. */
if (call_nr == PROC_EVENT) {
/* Assume FS got signal. Synchronize, but don't exit. */
do_sync();
/* PM tries to get FS to do something */
service_pm();
} else if (call_nr == SYN_ALARM) {
/* Alarm timer expired. Used only for select(). Check it. */
fs_expire_timers(m_in.NOTIFY_TIMESTAMP);
} else if ((call_nr & NOTIFY_MESSAGE)) {
/* Device notifies us of an event. */
dev_status(&m_in);
/* Device notifies us of an event. */
dev_status(&m_in);
} else {
/* Call the internal function that does the work. */
if (call_nr < 0 || call_nr >= NCALLS) {
@ -123,6 +126,7 @@ PRIVATE void get_work()
panic(__FILE__,"fs receive error", NO_NUM);
who_e = m_in.m_source;
who_p = _ENDPOINT_P(who_e);
if(who_p < -NR_TASKS || who_p >= NR_PROCS)
panic(__FILE__,"receive process out of range", who_p);
if(who_p >= 0 && fproc[who_p].fp_endpoint == NONE) {
@ -291,3 +295,123 @@ PRIVATE void init_root()
sp->s_rd_only = 0;
return;
}
/*===========================================================================*
* service_pm *
*===========================================================================*/
PRIVATE void service_pm()
{
int r, call;
message m;
/* Ask PM for work until there is nothing left to do */
for (;;)
{
m.m_type= PM_GET_WORK;
r= sendrec(PM_PROC_NR, &m);
if (r != OK)
{
panic("fs", "service_pm: sendrec failed", r);
}
if (m.m_type == PM_IDLE)
break;
call= m.m_type;
switch(call)
{
case PM_STIME:
boottime= m.PM_STIME_TIME;
/* No need to report status to PM */
break;
case PM_SETSID:
pm_setsid(m.PM_SETSID_PROC);
/* No need to report status to PM */
break;
case PM_SETGID:
pm_setgid(m.PM_SETGID_PROC, m.PM_SETGID_EGID,
m.PM_SETGID_RGID);
/* No need to report status to PM */
break;
case PM_SETUID:
pm_setuid(m.PM_SETUID_PROC, m.PM_SETUID_EGID,
m.PM_SETUID_RGID);
/* No need to report status to PM */
break;
case PM_FORK:
pm_fork(m.PM_FORK_PPROC, m.PM_FORK_CPROC,
m.PM_FORK_CPID);
/* No need to report status to PM */
break;
case PM_EXIT:
case PM_EXIT_TR:
pm_exit(m.PM_EXIT_PROC);
/* Reply dummy status to PM for synchronization */
m.m_type= (call == PM_EXIT_TR ? PM_EXIT_REPLY_TR :
PM_EXIT_REPLY);
/* Keep m.PM_EXIT_PROC */
r= send(PM_PROC_NR, &m);
if (r != OK)
panic(__FILE__, "service_pm: send failed", r);
break;
case PM_UNPAUSE:
case PM_UNPAUSE_TR:
unpause(m.PM_UNPAUSE_PROC);
/* No need to report status to PM */
break;
case PM_REBOOT:
pm_reboot();
/* Reply dummy status to PM for synchronization */
m.m_type= PM_REBOOT_REPLY;
r= send(PM_PROC_NR, &m);
if (r != OK)
panic(__FILE__, "service_pm: send failed", r);
break;
case PM_EXEC:
r= pm_exec(m.PM_EXEC_PROC, m.PM_EXEC_PATH,
m.PM_EXEC_PATH_LEN, m.PM_EXEC_FRAME,
m.PM_EXEC_FRAME_LEN);
/* Reply status to PM */
m.m_type= PM_EXEC_REPLY;
/* Keep m.PM_EXEC_PROC */
m.PM_EXEC_STATUS= r;
r= send(PM_PROC_NR, &m);
if (r != OK)
panic(__FILE__, "service_pm: send failed", r);
break;
case PM_DUMPCORE:
r= pm_dumpcore(m.PM_CORE_PROC,
(struct mem_map *)m.PM_CORE_SEGPTR);
/* Reply status to PM */
m.m_type= PM_CORE_REPLY;
/* Keep m.PM_CORE_PROC */
m.PM_CORE_STATUS= r;
r= send(PM_PROC_NR, &m);
if (r != OK)
panic(__FILE__, "service_pm: send failed", r);
break;
default:
panic("fs", "service_pm: unknown call", m.m_type);
}
}
}

View file

@ -7,14 +7,16 @@
* do_fcntl: perform the FCNTL system call
* do_sync: perform the SYNC system call
* do_fsync: perform the FSYNC system call
* do_reboot: sync disks and prepare for shutdown
* do_fork: adjust the tables after MM has performed a FORK system call
* pm_reboot: sync disks and prepare for shutdown
* pm_fork: adjust the tables after MM has performed a FORK system call
* do_exec: handle files with FD_CLOEXEC on after MM has done an EXEC
* do_exit: a process has exited; note that in the tables
* do_set: set uid or gid for some process
* pm_setgid: set group ids for some process
* pm_setuid: set user ids for some process
* do_revive: revive a process that was waiting for something (e.g. TTY)
* do_svrctl: file system control
* do_getsysinfo: request copy of FS data structure
* pm_dumpcore: create a core dump
*/
#include "fs.h"
@ -23,6 +25,7 @@
#include <minix/callnr.h>
#include <minix/endpoint.h>
#include <minix/com.h>
#include <sys/ptrace.h>
#include <sys/svrctl.h>
#include "buf.h"
#include "file.h"
@ -31,7 +34,15 @@
#include "param.h"
#include "super.h"
FORWARD _PROTOTYPE( int free_proc, (struct fproc *freed, int flags));
#define CORE_NAME "core"
#define CORE_MODE 0777 /* mode to use on core image files */
FORWARD _PROTOTYPE( void free_proc, (struct fproc *freed, int flags));
FORWARD _PROTOTYPE( int dumpcore, (int proc_e, struct mem_map *seg_ptr));
FORWARD _PROTOTYPE( int write_bytes, (struct inode *rip, off_t off,
char *buf, size_t bytes));
FORWARD _PROTOTYPE( int write_seg, (struct inode *rip, off_t off, int proc_e,
int seg, off_t seg_off, phys_bytes seg_bytes));
#define FP_EXITING 1
@ -252,18 +263,15 @@ PUBLIC int do_fsync()
}
/*===========================================================================*
* do_reboot *
* pm_reboot *
*===========================================================================*/
PUBLIC int do_reboot()
PUBLIC void pm_reboot()
{
/* Perform the FS side of the reboot call. */
int i;
struct super_block *sp;
struct inode dummy;
/* Only PM may make this call directly. */
if (who_e != PM_PROC_NR) return(EGENERIC);
/* Do exit processing for all leftover processes and servers,
* but don't actually exit them (if they were really gone, PM
* will tell us about it).
@ -291,35 +299,33 @@ PUBLIC int do_reboot()
/* Sync any unwritten buffers. */
do_sync();
return(OK);
}
/*===========================================================================*
* do_fork *
* pm_fork *
*===========================================================================*/
PUBLIC int do_fork()
PUBLIC void pm_fork(pproc, cproc, cpid)
int pproc; /* Parent process */
int cproc; /* Child process */
int cpid; /* Child process id */
{
/* Perform those aspects of the fork() system call that relate to files.
* In particular, let the child inherit its parent's file descriptors.
* The parent and child parameters tell who forked off whom. The file
* system uses the same slot numbers as the kernel. Only MM makes this call.
* system uses the same slot numbers as the kernel.
*/
register struct fproc *cp;
int i, parentno, childno;
/* Only PM may make this call directly. */
if (who_e != PM_PROC_NR) return(EGENERIC);
/* Check up-to-dateness of fproc. */
okendpt(m_in.parent_endpt, &parentno);
okendpt(pproc, &parentno);
/* PM gives child endpoint, which implies process slot information.
* Don't call isokendpt, because that will verify if the endpoint
* number is correct in fproc, which it won't be.
*/
childno = _ENDPOINT_P(m_in.child_endpt);
childno = _ENDPOINT_P(cproc);
if(childno < 0 || childno >= NR_PROCS)
panic(__FILE__, "FS: bogus child for forking", m_in.child_endpt);
if(fproc[childno].fp_pid != PID_FREE)
@ -334,68 +340,24 @@ PUBLIC int do_fork()
if (cp->fp_filp[i] != NIL_FILP) cp->fp_filp[i]->filp_count++;
/* Fill in new process and endpoint id. */
cp->fp_pid = m_in.pid;
cp->fp_endpoint = m_in.child_endpt;
cp->fp_pid = cpid;
cp->fp_endpoint = cproc;
/* A child is not a process leader. */
cp->fp_sesldr = 0;
/* This child has not exec()ced yet. */
cp->fp_execced = 0;
#if 0
printf("do_fork: child %d, slot %d\n", m_in.child_endpt, cp-fproc);
#endif
/* Record the fact that both root and working dir have another user. */
dup_inode(cp->fp_rootdir);
dup_inode(cp->fp_workdir);
return(OK);
}
/*===========================================================================*
* do_exec *
*===========================================================================*/
PUBLIC int do_exec()
{
/* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec). When
* MM does an EXEC, it calls FS to allow FS to find these files and close them.
*/
int i, proc;
long bitmap;
/* Only PM may make this call directly. */
if (who_e != PM_PROC_NR) return(EGENERIC);
/* The array of FD_CLOEXEC bits is in the fp_cloexec bit map. */
okendpt(m_in.endpt1, &proc);
fp = &fproc[proc]; /* get_filp() needs 'fp' */
bitmap = fp->fp_cloexec;
if (bitmap) {
/* Check the file desriptors one by one for presence of FD_CLOEXEC. */
for (i = 0; i < OPEN_MAX; i++) {
m_in.fd = i;
if ( (bitmap >> i) & 01) (void) do_close();
}
}
/* This child has now exec()ced. */
fp->fp_execced = 1;
/* Reply to caller (PM) directly. */
reply(who_e, OK);
/* Check if this is a driver that can now be useful. */
dmap_endpt_up(fp->fp_endpoint);
/* Suppress reply to caller (caller already replied to). */
return SUSPEND;
}
/*===========================================================================*
* free_proc *
*===========================================================================*/
PRIVATE int free_proc(struct fproc *exiter, int flags)
PRIVATE void free_proc(struct fproc *exiter, int flags)
{
int i, task;
register struct fproc *rfp;
@ -408,15 +370,13 @@ PRIVATE int free_proc(struct fproc *exiter, int flags)
if (fp->fp_suspended == SUSPENDED) {
task = -fp->fp_task;
if (task == XPIPE || task == XPOPEN) susp_count--;
m_in.ENDPT = fp->fp_endpoint;
(void) do_unpause(); /* this always succeeds for MM */
unpause(fp->fp_endpoint);
fp->fp_suspended = NOT_SUSPENDED;
}
/* Loop on file descriptors, closing any that are open. */
for (i = 0; i < OPEN_MAX; i++) {
m_in.fd = i;
(void) do_close();
(void) close_fd(fp, i);
}
/* Release root and working directories. */
@ -436,7 +396,7 @@ PRIVATE int free_proc(struct fproc *exiter, int flags)
* exit.
*/
if(!(flags & FP_EXITING))
return OK;
return;
dmap_unmap_by_endpt(fp->fp_endpoint);
/* Invalidate endpoint number for error and sanity checks. */
@ -467,53 +427,60 @@ PRIVATE int free_proc(struct fproc *exiter, int flags)
/* Exit done. Mark slot as free. */
fp->fp_pid = PID_FREE;
return(OK);
}
/*===========================================================================*
* do_exit *
* pm_exit *
*===========================================================================*/
PUBLIC int do_exit()
PUBLIC void pm_exit(proc)
int proc;
{
int exitee_p, exitee_e;
int exitee_p;
/* Perform the file system portion of the exit(status) system call. */
/* Only PM may do the EXIT call directly. */
if (who_e != PM_PROC_NR) return(EGENERIC);
/* Nevertheless, pretend that the call came from the user. */
exitee_e = m_in.endpt1;
okendpt(exitee_e, &exitee_p);
return free_proc(&fproc[exitee_p], FP_EXITING);
okendpt(proc, &exitee_p);
free_proc(&fproc[exitee_p], FP_EXITING);
}
/*===========================================================================*
* do_set *
* pm_setgid *
*===========================================================================*/
PUBLIC int do_set()
PUBLIC void pm_setgid(proc_e, egid, rgid)
int proc_e;
int egid;
int rgid;
{
/* Set uid_t or gid_t field. */
register struct fproc *tfp;
int proc;
int slot;
/* Only PM may make this call directly. */
if (who_e != PM_PROC_NR) return(EGENERIC);
okendpt(proc_e, &slot);
tfp = &fproc[slot];
okendpt(m_in.endpt1, &proc);
tfp = &fproc[proc];
if (call_nr == SETUID) {
tfp->fp_realuid = (uid_t) m_in.real_user_id;
tfp->fp_effuid = (uid_t) m_in.eff_user_id;
}
if (call_nr == SETGID) {
tfp->fp_effgid = (gid_t) m_in.eff_grp_id;
tfp->fp_realgid = (gid_t) m_in.real_grp_id;
}
return(OK);
tfp->fp_effgid = egid;
tfp->fp_realgid = rgid;
}
/*===========================================================================*
* pm_setuid *
*===========================================================================*/
PUBLIC void pm_setuid(proc_e, euid, ruid)
int proc_e;
int euid;
int ruid;
{
register struct fproc *tfp;
int slot;
okendpt(proc_e, &slot);
tfp = &fproc[slot];
tfp->fp_effuid = euid;
tfp->fp_realuid = ruid;
}
/*===========================================================================*
* do_revive *
*===========================================================================*/
@ -557,7 +524,7 @@ PUBLIC int do_svrctl()
/* Try to update device mapping. */
major = (device.dev >> MAJOR) & BYTE;
r=map_driver(major, who_e, device.style);
r=map_driver(major, who_e, device.style, 0 /* !force */);
if (r == OK)
{
/* If a driver has completed its exec(), it can be announced
@ -581,10 +548,283 @@ PUBLIC int do_svrctl()
(phys_bytes) sizeof(fdu))) != OK)
return(r);
major = (fdu.dev >> MAJOR) & BYTE;
r=map_driver(major, NONE, 0);
r=map_driver(major, NONE, 0, 0);
return(r);
}
default:
return(EINVAL);
}
}
/*===========================================================================*
* pm_dumpcore *
*===========================================================================*/
PUBLIC int pm_dumpcore(proc_e, seg_ptr)
int proc_e;
struct mem_map *seg_ptr;
{
int r, proc_s;
r= dumpcore(proc_e, seg_ptr);
/* Terminate the process */
okendpt(proc_e, &proc_s);
free_proc(&fproc[proc_s], FP_EXITING);
return r;
}
/*===========================================================================*
* dumpcore *
*===========================================================================*/
PRIVATE int dumpcore(proc_e, seg_ptr)
int proc_e;
struct mem_map *seg_ptr;
{
int r, seg, proc_s, exists;
mode_t omode;
vir_bytes len;
off_t off, seg_off;
long trace_off, trace_data;
struct fproc *rfp;
struct inode *rip, *ldirp;
struct mem_map segs[NR_LOCAL_SEGS];
okendpt(proc_e, &proc_s);
rfp= fp= &fproc[proc_s];
who_e= proc_e;
who_p= proc_s;
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
/* We need the equivalent of
* open(CORE_NAME, O_WRONLY|O_CREAT|O_TRUNC|O_NONBLOCK, CORE_MODE)
*/
/* Create a new inode by calling new_node(). */
omode = I_REGULAR | (CORE_MODE & ALL_MODES & rfp->fp_umask);
rip = new_node(&ldirp, CORE_NAME, omode, NO_ZONE, 0, NULL);
r = err_code;
put_inode(ldirp);
exists= (r == EEXIST);
if (r != OK && r != EEXIST) return(r); /* error */
/* Only do the normal open code if we didn't just create the file. */
if (exists) {
/* Check protections. */
r = forbidden(rip, W_BIT);
if (r != OK)
{
put_inode(rip);
return r;
}
/* Make sure it is a regular file */
switch (rip->i_mode & I_TYPE) {
case I_REGULAR:
break;
case I_DIRECTORY:
/* Directories may be read but not written. */
r = EISDIR;
break;
case I_CHAR_SPECIAL:
case I_BLOCK_SPECIAL:
case I_NAMED_PIPE:
r = EPERM;
break;
}
if (r != OK)
{
put_inode(rip);
return r;
}
/* Truncate the file */
truncate_inode(rip, 0);
wipe_inode(rip);
/* Send the inode from the inode cache to the
* block cache, so it gets written on the next
* cache flush.
*/
rw_inode(rip, WRITING);
}
/* Copy segments from PM */
r= sys_datacopy(PM_PROC_NR, (vir_bytes)seg_ptr,
SELF, (vir_bytes)segs, sizeof(segs));
if (r != OK) panic(__FILE__, "dumpcore: cannot copy segment info", r);
off= 0;
r= write_bytes(rip, off, (char *)segs, sizeof(segs));
if (r != OK)
{
put_inode(rip);
return r;
}
off += sizeof(segs);
/* Write out the whole kernel process table entry to get the regs. */
for (trace_off= 0;; trace_off += sizeof(long))
{
r= sys_trace(T_GETUSER, proc_e, trace_off, &trace_data);
if (r != OK)
{
printf("dumpcore: sys_trace failed at offset %d: %d\n",
trace_off, r);
break;
}
r= write_bytes(rip, off, (char *)&trace_data,
sizeof(trace_data));
if (r != OK)
{
put_inode(rip);
return r;
}
off += sizeof(trace_data);
}
/* Loop through segments and write the segments themselves out. */
for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
len= segs[seg].mem_len << CLICK_SHIFT;
seg_off= segs[seg].mem_vir << CLICK_SHIFT;
r= write_seg(rip, off, proc_e, seg, seg_off, len);
if (r != OK)
{
put_inode(rip);
return r;
}
off += len;
}
rip->i_size= off;
rip->i_dirt = DIRTY;
put_inode(rip);
return OK;
}
/*===========================================================================*
* write_bytes *
*===========================================================================*/
PRIVATE int write_bytes(rip, off, buf, bytes)
struct inode *rip; /* inode descriptor to read from */
off_t off; /* offset in file */
char *buf;
size_t bytes; /* how much is to be transferred? */
{
int r, block_size;
off_t n, o, b_off;
block_t b;
struct buf *bp;
block_size= rip->i_sp->s_block_size;
for (o= off - (off % block_size); o < off+bytes; o += block_size)
{
if (o < off)
b_off= off-o;
else
b_off= 0;
n= block_size-b_off;
if (o+b_off+n > off+bytes)
n= off+bytes-(o+b_off);
b = read_map(rip, o);
if (b == NO_BLOCK) {
/* Writing to a nonexistent block. Create and enter
* in inode.
*/
if ((bp= new_block(rip, o)) == NIL_BUF)
return(err_code);
}
else
{
/* Just read the block, no need to optimize for
* writing entire blocks.
*/
bp = get_block(rip->i_dev, b, NORMAL);
}
if (n != block_size && o >= rip->i_size && b_off == 0) {
zero_block(bp);
}
/* Copy a chunk from user space to the block buffer. */
memcpy((bp->b_data+b_off), buf, n);
bp->b_dirt = DIRTY;
if (b_off + n == block_size)
put_block(bp, FULL_DATA_BLOCK);
else
put_block(bp, PARTIAL_DATA_BLOCK);
buf += n;
}
return OK;
}
/*===========================================================================*
* write_seg *
*===========================================================================*/
PRIVATE int write_seg(rip, off, proc_e, seg, seg_off, seg_bytes)
struct inode *rip; /* inode descriptor to read from */
off_t off; /* offset in file */
int proc_e; /* process number (endpoint) */
int seg; /* T, D, or S */
off_t seg_off; /* Offset in segment */
phys_bytes seg_bytes; /* how much is to be transferred? */
{
int r, block_size, fl;
off_t n, o, b_off;
block_t b;
struct buf *bp;
block_size= rip->i_sp->s_block_size;
for (o= off - (off % block_size); o < off+seg_bytes; o += block_size)
{
if (o < off)
b_off= off-o;
else
b_off= 0;
n= block_size-b_off;
if (o+b_off+n > off+seg_bytes)
n= off+seg_bytes-(o+b_off);
b = read_map(rip, o);
if (b == NO_BLOCK) {
/* Writing to a nonexistent block. Create and enter in inode.*/
if ((bp= new_block(rip, o)) == NIL_BUF)
return(err_code);
} else {
/* Normally an existing block to be partially overwritten is
* first read in. However, a full block need not be read in.
* If it is already in the cache, acquire it, otherwise just
* acquire a free buffer.
*/
fl = (n == block_size ? NO_READ : NORMAL);
bp = get_block(rip->i_dev, b, fl);
}
if (n != block_size && o >= rip->i_size && b_off == 0) {
zero_block(bp);
}
/* Copy a chunk from user space to the block buffer. */
r = sys_vircopy(proc_e, seg, (phys_bytes) seg_off,
FS_PROC_NR, D, (phys_bytes) (bp->b_data+b_off),
(phys_bytes) n);
bp->b_dirt = DIRTY;
fl = (b_off + n == block_size ? FULL_DATA_BLOCK : PARTIAL_DATA_BLOCK);
put_block(bp, fl);
seg_off += n;
}
return OK;
}

View file

@ -8,6 +8,7 @@
* do_mkdir: perform the MKDIR system call
* do_close: perform the CLOSE system call
* do_lseek: perform the LSEEK system call
* new_node: create a new file, directory, etc.
*/
#include "fs.h"
@ -31,8 +32,6 @@ PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode) );
FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,mode_t bits,int oflags));
FORWARD _PROTOTYPE( struct inode *new_node, (struct inode **ldirp,
char *path, mode_t bits, zone_t z0, int opaque, char *string));
/*===========================================================================*
* do_creat *
@ -200,7 +199,7 @@ PRIVATE int common_open(register int oflags, mode_t omode)
/*===========================================================================*
* new_node *
*===========================================================================*/
PRIVATE struct inode *new_node(struct inode **ldirp,
PUBLIC struct inode *new_node(struct inode **ldirp,
char *path, mode_t bits, zone_t z0, int opaque, char *parsed)
{
/* New_node() is called by common_open(), do_mknod(), and do_mkdir().
@ -389,6 +388,17 @@ PUBLIC int do_mkdir()
PUBLIC int do_close()
{
/* Perform the close(fd) system call. */
return close_fd(fp, m_in.fd);
}
/*===========================================================================*
* close_fd *
*===========================================================================*/
PUBLIC int close_fd(rfp, fd_nr)
struct fproc *rfp;
int fd_nr;
{
/* Close a filedescriptor for a process. */
register struct filp *rfilp;
register struct inode *rip;
@ -397,7 +407,7 @@ PUBLIC int do_close()
dev_t dev;
/* First locate the inode that belongs to the file descriptor. */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
if ( (rfilp = get_filp2(rfp, fd_nr)) == NIL_FILP) return(err_code);
rip = rfilp->filp_ino; /* 'rip' points to the inode */
if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) {
@ -440,16 +450,16 @@ PUBLIC int do_close()
put_inode(rip);
}
fp->fp_cloexec &= ~(1L << m_in.fd); /* turn off close-on-exec bit */
fp->fp_filp[m_in.fd] = NIL_FILP;
FD_CLR(m_in.fd, &fp->fp_filp_inuse);
rfp->fp_cloexec &= ~(1L << fd_nr); /* turn off close-on-exec bit */
rfp->fp_filp[fd_nr] = NIL_FILP;
FD_CLR(fd_nr, &rfp->fp_filp_inuse);
/* Check to see if the file is locked. If so, release all locks. */
if (nr_locks == 0) return(OK);
lock_count = nr_locks; /* save count of locks */
for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
if (flp->lock_type == 0) continue; /* slot not in use */
if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) {
if (flp->lock_inode == rip && flp->lock_pid == rfp->fp_pid) {
flp->lock_type = 0;
nr_locks--;
}

View file

@ -34,6 +34,7 @@
#define driver_nr m4_l2
#define dev_nr m4_l3
#define dev_style m4_l4
#define m_force m4_l5
#define rd_only m1_i3
#define real_user_id m1_i2
#define request m1_i2

View file

@ -328,18 +328,32 @@ int returned; /* if hanging on task, how many bytes read */
*===========================================================================*/
PUBLIC int do_unpause()
{
/* A signal has been sent to a user who is paused on the file system.
* Abort the system call with the EINTR error message.
*/
int proc_nr_e;
if (who_e != PM_PROC_NR) return(EPERM);
proc_nr_e = m_in.ENDPT;
return unpause(proc_nr_e);
}
/*===========================================================================*
* unpause *
*===========================================================================*/
PUBLIC int unpause(proc_nr_e)
int proc_nr_e;
{
/* A signal has been sent to a user who is paused on the file system.
* Abort the system call with the EINTR error message.
*/
register struct fproc *rfp;
int proc_nr_e, proc_nr_p, task, fild;
int proc_nr_p, task, fild;
struct filp *f;
dev_t dev;
message mess;
if (who_e != PM_PROC_NR) return(EPERM);
proc_nr_e = m_in.ENDPT;
okendpt(proc_nr_e, &proc_nr_p);
rfp = &fproc[proc_nr_p];
if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);

View file

@ -5,6 +5,7 @@
/* Structs used in prototypes must be declared as such first. */
struct buf;
struct filp;
struct fproc;
struct inode;
struct super_block;
@ -29,6 +30,8 @@ _PROTOTYPE( void invalidate2, (Dev_t device) );
/* device.c */
_PROTOTYPE( int dev_open, (Dev_t dev, int proc, int flags) );
_PROTOTYPE( void dev_close, (Dev_t dev) );
_PROTOTYPE( int dev_bio, (int op, Dev_t dev, int proc, void *buf,
off_t pos, int bytes, int flags) );
_PROTOTYPE( int dev_io, (int op, Dev_t dev, int proc, void *buf,
off_t pos, int bytes, int flags) );
_PROTOTYPE( int gen_opcl, (int op, Dev_t dev, int proc, int flags) );
@ -40,7 +43,7 @@ _PROTOTYPE( int ctty_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int clone_opcl, (int op, Dev_t dev, int proc, int flags) );
_PROTOTYPE( int ctty_io, (int task_nr, message *mess_ptr) );
_PROTOTYPE( int do_ioctl, (void) );
_PROTOTYPE( int do_setsid, (void) );
_PROTOTYPE( void pm_setsid, (int proc_e) );
_PROTOTYPE( void dev_status, (message *) );
_PROTOTYPE( void dev_up, (int major) );
@ -49,16 +52,24 @@ _PROTOTYPE( int do_fkey_pressed, (void) );
/* dmap.c */
_PROTOTYPE( int do_devctl, (void) );
_PROTOTYPE( int fs_devctl, (int req, int dev, int proc_nr_e, int style,
int force) );
_PROTOTYPE( void build_dmap, (void) );
_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style) );
_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style,
int force) );
_PROTOTYPE( int dmap_driver_match, (int proc, int major) );
_PROTOTYPE( void dmap_unmap_by_endpt, (int proc_nr) );
_PROTOTYPE( void dmap_endpt_up, (int proc_nr) );
/* exec.c */
_PROTOTYPE( int pm_exec, (int proc_e, char *path, vir_bytes path_len,
char *frame, vir_bytes frame_len) );
/* filedes.c */
_PROTOTYPE( struct filp *find_filp, (struct inode *rip, mode_t bits) );
_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, struct filp **fpt) );
_PROTOTYPE( struct filp *get_filp, (int fild) );
_PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) );
_PROTOTYPE( int inval_filp, (struct filp *) );
/* inode.c */
@ -90,17 +101,18 @@ _PROTOTYPE( void reply, (int whom, int result) );
/* misc.c */
_PROTOTYPE( int do_dup, (void) );
_PROTOTYPE( int do_exit, (void) );
_PROTOTYPE( void pm_exit, (int proc) );
_PROTOTYPE( int do_fcntl, (void) );
_PROTOTYPE( int do_fork, (void) );
_PROTOTYPE( int do_exec, (void) );
_PROTOTYPE( void pm_fork, (int pproc, int cproc, int cpid) );
_PROTOTYPE( int do_revive, (void) );
_PROTOTYPE( int do_set, (void) );
_PROTOTYPE( void pm_setgid, (int proc_e, int egid, int rgid) );
_PROTOTYPE( void pm_setuid, (int proc_e, int euid, int ruid) );
_PROTOTYPE( int do_sync, (void) );
_PROTOTYPE( int do_fsync, (void) );
_PROTOTYPE( int do_reboot, (void) );
_PROTOTYPE( void pm_reboot, (void) );
_PROTOTYPE( int do_svrctl, (void) );
_PROTOTYPE( int do_getsysinfo, (void) );
_PROTOTYPE( int pm_dumpcore, (int proc_e, struct mem_map *seg_ptr) );
/* mount.c */
_PROTOTYPE( int do_mount, (void) );
@ -109,12 +121,15 @@ _PROTOTYPE( int unmount, (Dev_t dev) );
/* open.c */
_PROTOTYPE( int do_close, (void) );
_PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) );
_PROTOTYPE( int do_creat, (void) );
_PROTOTYPE( int do_lseek, (void) );
_PROTOTYPE( int do_mknod, (void) );
_PROTOTYPE( int do_mkdir, (void) );
_PROTOTYPE( int do_open, (void) );
_PROTOTYPE( int do_slink, (void) );
_PROTOTYPE( int do_slink, (void) );
_PROTOTYPE( struct inode *new_node, (struct inode **ldirp,
char *path, mode_t bits, zone_t z0, int opaque, char *string) );
/* path.c */
_PROTOTYPE( struct inode *advance,(struct inode **dirp, char string[NAME_MAX]));
@ -128,6 +143,7 @@ _PROTOTYPE( struct inode *parse_path, (char *path, char string[NAME_MAX],
/* pipe.c */
_PROTOTYPE( int do_pipe, (void) );
_PROTOTYPE( int do_unpause, (void) );
_PROTOTYPE( int unpause, (int proc_nr_e) );
_PROTOTYPE( int pipe_check, (struct inode *rip, int rw_flag,
int oflags, int bytes, off_t position, int *canwrite, int notouch));
_PROTOTYPE( void release, (struct inode *ip, int call_nr, int count) );
@ -211,6 +227,3 @@ _PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta, tmr_func_t watchdog, int
_PROTOTYPE( void fs_expire_timers, (clock_t now) );
_PROTOTYPE( void fs_cancel_timer, (timer_t *tp) );
_PROTOTYPE( void fs_init_timer, (timer_t *tp) );
/* cdprobe.c */
_PROTOTYPE( int cdprobe, (void) );

View file

@ -16,8 +16,8 @@
PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 0 = unused */
do_exit, /* 1 = exit */
do_fork, /* 2 = fork */
no_sys, /* 1 = (exit) */
no_sys, /* 2 = (fork) */
do_read, /* 3 = read */
do_write, /* 4 = write */
do_open, /* 5 = open */
@ -38,7 +38,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 20 = getpid */
do_mount, /* 21 = mount */
do_umount, /* 22 = umount */
do_set, /* 23 = setuid */
no_sys, /* 23 = (setuid) */
no_sys, /* 24 = getuid */
do_stime, /* 25 = stime */
no_sys, /* 26 = ptrace */
@ -61,7 +61,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 43 = times */
no_sys, /* 44 = (prof) */
do_slink, /* 45 = symlink */
do_set, /* 46 = setgid */
no_sys, /* 46 = (setgid) */
no_sys, /* 47 = getgid */
no_sys, /* 48 = (signal)*/
do_rdlink, /* 49 = readlink*/
@ -74,10 +74,10 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 56 = (mpx) */
no_sys, /* 57 = unused */
no_sys, /* 58 = unused */
do_exec, /* 59 = execve */
no_sys, /* 59 = (execve) */
do_umask, /* 60 = umask */
do_chroot, /* 61 = chroot */
do_setsid, /* 62 = setsid */
no_sys, /* 62 = (setsid) */
no_sys, /* 63 = getpgrp */
no_sys, /* 64 = KSIG: signals originating in the kernel */
@ -92,7 +92,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 73 = sigpending */
no_sys, /* 74 = sigprocmask */
no_sys, /* 75 = sigreturn */
do_reboot, /* 76 = reboot */
no_sys, /* 76 = (reboot) */
do_svrctl, /* 77 = svrctl */
no_sys, /* 78 = unused */

View file

@ -24,7 +24,7 @@
#define STACK_CHANGED 2 /* flag value when stack size changed */
/*===========================================================================*
* do_brk *
* do_brk *
*===========================================================================*/
PUBLIC int do_brk()
{
@ -57,7 +57,7 @@ PUBLIC int do_brk()
}
/*===========================================================================*
* adjust *
* adjust *
*===========================================================================*/
PUBLIC int adjust(rmp, data_clicks, sp)
register struct mproc *rmp; /* whose memory is being adjusted? */
@ -79,12 +79,13 @@ vir_bytes sp; /* new value of sp */
mem_sp = &rmp->mp_seg[S]; /* pointer to stack segment map */
changed = 0; /* set when either segment changed */
if (mem_sp->mem_len == 0) return(OK); /* don't bother init */
/* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
sp_click = sp >> CLICK_SHIFT; /* click containing sp */
if (sp_click >= base_of_stack) return(ENOMEM); /* sp too high */
if (sp_click >= base_of_stack)
{
return(ENOMEM); /* sp too high */
}
/* Compute size of gap between stack and data segments. */
delta = (long) mem_sp->mem_vir - (long) sp_click;
@ -94,7 +95,10 @@ vir_bytes sp; /* new value of sp */
#define SAFETY_BYTES (384 * sizeof(char *))
#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
if (lower < gap_base) return(ENOMEM); /* data and stack collided */
if (lower < gap_base)
{
return(ENOMEM); /* data and stack collided */
}
/* Update data length (but not data orgin) on behalf of brk() system call. */
old_clicks = mem_dp->mem_len;

View file

@ -19,3 +19,5 @@
#define PM_PID 0 /* PM's process id number */
#define INIT_PID 1 /* INIT's process id number */
#define DUMPED 0200 /* bit set in status when core dumped */

View file

@ -12,7 +12,9 @@
*
* The entry points into this file are:
* do_exec: perform the EXEC system call
* rw_seg: read or write a segment from or to a file
* exec_newmem: allocate new memory map for a process that tries to exec
* do_execrestart: finish the special exec call for RS
* exec_restart: finish a regular exec call
* find_share: find a process whose text segment can be shared
*/
@ -27,18 +29,9 @@
#include "mproc.h"
#include "param.h"
FORWARD _PROTOTYPE( int new_mem, (struct mproc *sh_mp, vir_bytes text_bytes,
vir_bytes data_bytes, vir_bytes bss_bytes,
vir_bytes stk_bytes, phys_bytes tot_bytes) );
FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX], vir_bytes base) );
FORWARD _PROTOTYPE( int insert_arg, (char stack[ARG_MAX],
vir_bytes *stk_bytes, char *arg, int replace) );
FORWARD _PROTOTYPE( char *patch_stack, (int fd, char stack[ARG_MAX],
vir_bytes *stk_bytes, char *script) );
FORWARD _PROTOTYPE( int read_header, (int fd, int *ft, vir_bytes *text_bytes,
vir_bytes *data_bytes, vir_bytes *bss_bytes,
phys_bytes *tot_bytes, long *sym_bytes, vir_clicks sc,
vir_bytes *pc) );
FORWARD _PROTOTYPE( int new_mem, (struct mproc *rmp, struct mproc *sh_mp,
vir_bytes text_bytes, vir_bytes data_bytes, vir_bytes bss_bytes,
vir_bytes stk_bytes, phys_bytes tot_bytes) );
#define ESCRIPT (-2000) /* Returned by read_header for a #! script. */
#define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
@ -48,250 +41,236 @@ FORWARD _PROTOTYPE( int read_header, (int fd, int *ft, vir_bytes *text_bytes,
*===========================================================================*/
PUBLIC int do_exec()
{
/* Perform the execve(name, argv, envp) call. The user library builds a
* complete stack image, including pointers, args, environ, etc. The stack
* is copied to a buffer inside PM, and then to the new core image.
*/
register struct mproc *rmp;
struct mproc *sh_mp;
int m, r, r2, fd, ft, sn;
static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
static char name_buf[PATH_MAX]; /* the name of the file to exec */
char *new_sp, *name, *basename;
vir_bytes src, dst, text_bytes, data_bytes, bss_bytes, stk_bytes, vsp;
phys_bytes tot_bytes; /* total space for program, including gap */
long sym_bytes;
vir_clicks sc;
struct stat s_buf[2], *s_p;
vir_bytes pc;
int r;
/* Do some validity checks. */
rmp = mp;
stk_bytes = (vir_bytes) m_in.stack_bytes;
if (stk_bytes > ARG_MAX) return(ENOMEM); /* stack too big */
if (m_in.exec_len <= 0 || m_in.exec_len > PATH_MAX) return(EINVAL);
/* Save parameters */
mp->mp_exec_path= m_in.exec_name;
mp->mp_exec_path_len= m_in.exec_len;
mp->mp_exec_frame= m_in.stack_ptr;
mp->mp_exec_frame_len= m_in.stack_bytes;
/* Get the exec file name and see if the file is executable. */
src = (vir_bytes) m_in.exec_name;
dst = (vir_bytes) name_buf;
r = sys_datacopy(who_e, (vir_bytes) src,
PM_PROC_NR, (vir_bytes) dst, (phys_bytes) m_in.exec_len);
if (r != OK) return(r); /* file name not in user data segment */
/* Fetch the stack from the user before destroying the old core image. */
src = (vir_bytes) m_in.stack_ptr;
dst = (vir_bytes) mbuf;
r = sys_datacopy(who_e, (vir_bytes) src,
PM_PROC_NR, (vir_bytes) dst, (phys_bytes)stk_bytes);
/* can't fetch stack (e.g. bad virtual addr) */
if (r != OK) return(EACCES);
r = 0; /* r = 0 (first attempt), or 1 (interpreted script) */
name = name_buf; /* name of file to exec. */
do {
s_p = &s_buf[r];
tell_fs(CHDIR, who_e, FALSE, 0); /* switch to the user's FS environ */
fd = allowed(name, s_p, X_BIT); /* is file executable? */
if (fd < 0) return(fd); /* file was not executable */
/* Read the file header and extract the segment sizes. */
sc = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
m = read_header(fd, &ft, &text_bytes, &data_bytes, &bss_bytes,
&tot_bytes, &sym_bytes, sc, &pc);
if (m != ESCRIPT || ++r > 1) break;
} while ((name = patch_stack(fd, mbuf, &stk_bytes, name_buf)) != NULL);
if (m < 0) {
close(fd); /* something wrong with header */
return(stk_bytes > ARG_MAX ? ENOMEM : ENOEXEC);
}
/* Can the process' text be shared with that of one already running? */
sh_mp = find_share(rmp, s_p->st_ino, s_p->st_dev, s_p->st_ctime);
/* Allocate new memory and release old memory. Fix map and tell kernel. */
r = new_mem(sh_mp, text_bytes, data_bytes, bss_bytes, stk_bytes, tot_bytes);
if (r != OK) {
close(fd); /* insufficient core or program too big */
return(r);
}
/* Save file identification to allow it to be shared. */
rmp->mp_ino = s_p->st_ino;
rmp->mp_dev = s_p->st_dev;
rmp->mp_ctime = s_p->st_ctime;
/* Patch up stack and copy it from PM to new core image. */
vsp = (vir_bytes) rmp->mp_seg[S].mem_vir << CLICK_SHIFT;
vsp += (vir_bytes) rmp->mp_seg[S].mem_len << CLICK_SHIFT;
vsp -= stk_bytes;
patch_ptr(mbuf, vsp);
src = (vir_bytes) mbuf;
r = sys_datacopy(PM_PROC_NR, (vir_bytes) src,
who_e, (vir_bytes) vsp, (phys_bytes)stk_bytes);
if (r != OK) panic(__FILE__,"do_exec stack copy err on", who_e);
/* Read in text and data segments. */
if (sh_mp != NULL) {
lseek(fd, (off_t) text_bytes, SEEK_CUR); /* shared: skip text */
} else {
rw_seg(0, fd, who_e, T, text_bytes);
}
rw_seg(0, fd, who_e, D, data_bytes);
close(fd); /* don't need exec file any more */
/* Take care of setuid/setgid bits. */
if ((rmp->mp_flags & TRACED) == 0) { /* suppress if tracing */
if (s_buf[0].st_mode & I_SET_UID_BIT) {
rmp->mp_effuid = s_buf[0].st_uid;
tell_fs(SETUID, who_e, (int)rmp->mp_realuid, (int)rmp->mp_effuid);
/* Forward call to FS */
if (mp->mp_fs_call != PM_IDLE)
{
panic(__FILE__, "do_exec: not idle", mp->mp_fs_call);
}
if (s_buf[0].st_mode & I_SET_GID_BIT) {
rmp->mp_effgid = s_buf[0].st_gid;
tell_fs(SETGID,who_e, (int)rmp->mp_realgid, (int)rmp->mp_effgid);
mp->mp_fs_call= PM_EXEC;
r= notify(FS_PROC_NR);
if (r != OK)
panic(__FILE__, "do_getset: unable to notify FS", r);
/* Do not reply */
return SUSPEND;
}
/*===========================================================================*
* exec_newmem *
*===========================================================================*/
PUBLIC int exec_newmem()
{
int r, proc_e, proc_n, allow_setuid;
vir_bytes stack_top;
vir_clicks tc, dc, sc, totc, dvir, s_vir;
struct mproc *rmp, *sh_mp;
char *ptr;
struct exec_newmem args;
if (who_e != FS_PROC_NR && who_e != RS_PROC_NR)
return EPERM;
proc_e= m_in.EXC_NM_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
panic(__FILE__, "exec_newmem: got bad endpoint",
proc_e);
}
}
rmp= &mproc[proc_n];
/* Save offset to initial argc (for ps) */
rmp->mp_procargs = vsp;
ptr= m_in.EXC_NM_PTR;
r= sys_datacopy(who_e, (vir_bytes)ptr,
SELF, (vir_bytes)&args, sizeof(args));
if (r != OK)
panic(__FILE__, "exec_newmem: sys_datacopy failed", r);
/* Fix 'mproc' fields, tell kernel that exec is done, reset caught sigs. */
for (sn = 1; sn <= _NSIG; sn++) {
if (sigismember(&rmp->mp_catch, sn)) {
sigdelset(&rmp->mp_catch, sn);
rmp->mp_sigact[sn].sa_handler = SIG_DFL;
sigemptyset(&rmp->mp_sigact[sn].sa_mask);
/* Check to see if segment sizes are feasible. */
tc = ((unsigned long) args.text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
dc = (args.data_bytes+args.bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
totc = (args.tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
sc = (args.args_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
if (dc >= totc) return(ENOEXEC); /* stack must be at least 1 click */
dvir = (args.sep_id ? 0 : tc);
s_vir = dvir + (totc - sc);
#if (CHIP == INTEL && _WORD_SIZE == 2)
r = size_ok(*ft, tc, dc, sc, dvir, s_vir);
#else
r = (dvir + dc > s_vir) ? ENOMEM : OK;
#endif
if (r != OK)
return r;
/* Can the process' text be shared with that of one already running? */
sh_mp = find_share(rmp, args.st_ino, args.st_dev, args.st_ctime);
/* Allocate new memory and release old memory. Fix map and tell
* kernel.
*/
r = new_mem(rmp, sh_mp, args.text_bytes, args.data_bytes,
args.bss_bytes, args.args_bytes, args.tot_bytes);
if (r != OK) return(r);
rmp->mp_flags |= PARTIAL_EXEC; /* Kill process if something goes
* wrong after this point.
*/
/* Save file identification to allow it to be shared. */
rmp->mp_ino = args.st_ino;
rmp->mp_dev = args.st_dev;
rmp->mp_ctime = args.st_ctime;
stack_top= ((vir_bytes)rmp->mp_seg[S].mem_vir << CLICK_SHIFT) +
((vir_bytes)rmp->mp_seg[S].mem_len << CLICK_SHIFT);
/* Save offset to initial argc (for ps) */
rmp->mp_procargs = stack_top - args.args_bytes;
/* set/clear separate I&D flag */
if (args.sep_id)
rmp->mp_flags |= SEPARATE;
else
rmp->mp_flags &= ~SEPARATE;
allow_setuid= 0; /* Do not allow setuid execution */
if ((rmp->mp_flags & TRACED) == 0) {
/* Okay, setuid execution is allowed */
allow_setuid= 1;
rmp->mp_effuid = args.new_uid;
rmp->mp_effgid = args.new_gid;
}
}
rmp->mp_flags &= ~SEPARATE; /* turn off SEPARATE bit */
rmp->mp_flags |= ft; /* turn it on for separate I & D files */
new_sp = (char *) vsp;
/* System will save command line for debugging, ps(1) output, etc. */
strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
rmp->mp_name[PROC_NAME_LEN-1] = '\0';
tell_fs(EXEC, who_e, 0, 0); /* allow FS to handle FD_CLOEXEC files */
mp->mp_reply.reply_res2= stack_top;
mp->mp_reply.reply_res3= 0;
if (!sh_mp) /* Load text if sh_mp = NULL */
mp->mp_reply.reply_res3 |= EXC_NM_RF_LOAD_TEXT;
if (allow_setuid)
mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID;
/* System will save command line for debugging, ps(1) output, etc. */
basename = strrchr(name, '/');
if (basename == NULL) basename = name; else basename++;
strncpy(rmp->mp_name, basename, PROC_NAME_LEN-1);
rmp->mp_name[PROC_NAME_LEN] = '\0';
if((r2=sys_exec(who_e, new_sp, basename, pc)) != OK) {
panic(__FILE__,"sys_exec failed", r2);
}
return OK;
}
/* Cause a signal if this process is traced. */
if (rmp->mp_flags & TRACED) check_sig(rmp->mp_pid, SIGTRAP);
return(SUSPEND); /* no reply, new program just runs */
/*===========================================================================*
* do_execrestart *
*===========================================================================*/
PUBLIC int do_execrestart()
{
int proc_e, proc_n, result;
struct mproc *rmp;
if (who_e != RS_PROC_NR)
return EPERM;
proc_e= m_in.EXC_RS_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
panic(__FILE__, "do_execrestart: got bad endpoint",
proc_e);
}
rmp= &mproc[proc_n];
result= m_in.EXC_RS_RESULT;
exec_restart(rmp, result);
return OK;
}
/*===========================================================================*
* exec_restart *
*===========================================================================*/
PUBLIC void exec_restart(rmp, result)
struct mproc *rmp;
int result;
{
int r, sn;
vir_bytes pc;
char *new_sp;
if (result != OK)
{
if (rmp->mp_flags & PARTIAL_EXEC)
{
printf("partial exec; killing process\n");
/* Use SIGILL signal that something went wrong */
rmp->mp_sigstatus = SIGILL;
pm_exit(rmp, 0, FALSE /*!for_trace*/);
return;
}
setreply(rmp-mproc, result);
return;
}
rmp->mp_flags &= ~PARTIAL_EXEC;
/* Fix 'mproc' fields, tell kernel that exec is done, reset caught
* sigs.
*/
for (sn = 1; sn <= _NSIG; sn++) {
if (sigismember(&rmp->mp_catch, sn)) {
sigdelset(&rmp->mp_catch, sn);
rmp->mp_sigact[sn].sa_handler = SIG_DFL;
sigemptyset(&rmp->mp_sigact[sn].sa_mask);
}
}
new_sp= (char *)rmp->mp_procargs;
pc= 0; /* for now */
r= sys_exec(rmp->mp_endpoint, new_sp, rmp->mp_name, pc);
if (r != OK) panic(__FILE__, "sys_exec failed", r);
/* Cause a signal if this process is traced. */
if (rmp->mp_flags & TRACED) check_sig(rmp->mp_pid, SIGTRAP);
}
/*===========================================================================*
* read_header *
* find_share *
*===========================================================================*/
PRIVATE int read_header(fd, ft, text_bytes, data_bytes, bss_bytes,
tot_bytes, sym_bytes, sc, pc)
int fd; /* file descriptor for reading exec file */
int *ft; /* place to return ft number */
vir_bytes *text_bytes; /* place to return text size */
vir_bytes *data_bytes; /* place to return initialized data size */
vir_bytes *bss_bytes; /* place to return bss size */
phys_bytes *tot_bytes; /* place to return total size */
long *sym_bytes; /* place to return symbol table size */
vir_clicks sc; /* stack size in clicks */
vir_bytes *pc; /* program entry point (initial PC) */
PUBLIC struct mproc *find_share(mp_ign, ino, dev, ctime)
struct mproc *mp_ign; /* process that should not be looked at */
ino_t ino; /* parameters that uniquely identify a file */
dev_t dev;
time_t ctime;
{
/* Read the header and extract the text, data, bss and total sizes from it. */
/* Look for a process that is the file <ino, dev, ctime> in execution. Don't
* accidentally "find" mp_ign, because it is the process on whose behalf this
* call is made.
*/
struct mproc *sh_mp;
for (sh_mp = &mproc[0]; sh_mp < &mproc[NR_PROCS]; sh_mp++) {
int m, ct;
vir_clicks tc, dc, s_vir, dvir;
phys_clicks totc;
struct exec hdr; /* a.out header is read in here */
/* Read the header and check the magic number. The standard MINIX header
* is defined in <a.out.h>. It consists of 8 chars followed by 6 longs.
* Then come 4 more longs that are not used here.
* Byte 0: magic number 0x01
* Byte 1: magic number 0x03
* Byte 2: normal = 0x10 (not checked, 0 is OK), separate I/D = 0x20
* Byte 3: CPU type, Intel 16 bit = 0x04, Intel 32 bit = 0x10,
* Motorola = 0x0B, Sun SPARC = 0x17
* Byte 4: Header length = 0x20
* Bytes 5-7 are not used.
*
* Now come the 6 longs
* Bytes 8-11: size of text segments in bytes
* Bytes 12-15: size of initialized data segment in bytes
* Bytes 16-19: size of bss in bytes
* Bytes 20-23: program entry point
* Bytes 24-27: total memory allocated to program (text, data + stack)
* Bytes 28-31: size of symbol table in bytes
* The longs are represented in a machine dependent order,
* little-endian on the 8088, big-endian on the 68000.
* The header is followed directly by the text and data segments, and the
* symbol table (if any). The sizes are given in the header. Only the
* text and data segments are copied into memory by exec. The header is
* used here only. The symbol table is for the benefit of a debugger and
* is ignored here.
*/
if ((m= read(fd, &hdr, A_MINHDR)) < 2) return(ENOEXEC);
/* Interpreted script? */
if (((char *) &hdr)[0] == '#' && ((char *) &hdr)[1] == '!') return(ESCRIPT);
if (m != A_MINHDR) return(ENOEXEC);
/* Check magic number, cpu type, and flags. */
if (BADMAG(hdr)) return(ENOEXEC);
#if (CHIP == INTEL && _WORD_SIZE == 2)
if (hdr.a_cpu != A_I8086) return(ENOEXEC);
#endif
#if (CHIP == INTEL && _WORD_SIZE == 4)
if (hdr.a_cpu != A_I80386) return(ENOEXEC);
#endif
if ((hdr.a_flags & ~(A_NSYM | A_EXEC | A_SEP)) != 0) return(ENOEXEC);
*ft = ( (hdr.a_flags & A_SEP) ? SEPARATE : 0); /* separate I & D or not */
/* Get text and data sizes. */
*text_bytes = (vir_bytes) hdr.a_text; /* text size in bytes */
*data_bytes = (vir_bytes) hdr.a_data; /* data size in bytes */
*bss_bytes = (vir_bytes) hdr.a_bss; /* bss size in bytes */
*tot_bytes = hdr.a_total; /* total bytes to allocate for prog */
*sym_bytes = hdr.a_syms; /* symbol table size in bytes */
if (*tot_bytes == 0) return(ENOEXEC);
if (*ft != SEPARATE) {
/* If I & D space is not separated, it is all considered data. Text=0*/
*data_bytes += *text_bytes;
*text_bytes = 0;
if (!(sh_mp->mp_flags & SEPARATE)) continue;
if (sh_mp == mp_ign) continue;
if (sh_mp->mp_ino != ino) continue;
if (sh_mp->mp_dev != dev) continue;
if (sh_mp->mp_ctime != ctime) continue;
return sh_mp;
}
*pc = hdr.a_entry; /* initial address to start execution */
/* Check to see if segment sizes are feasible. */
tc = ((unsigned long) *text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
dc = (*data_bytes + *bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
totc = (*tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
if (dc >= totc) return(ENOEXEC); /* stack must be at least 1 click */
dvir = (*ft == SEPARATE ? 0 : tc);
s_vir = dvir + (totc - sc);
#if (CHIP == INTEL && _WORD_SIZE == 2)
m = size_ok(*ft, tc, dc, sc, dvir, s_vir);
#else
m = (dvir + dc > s_vir) ? ENOMEM : OK;
#endif
ct = hdr.a_hdrlen & BYTE; /* header length */
if (ct > A_MINHDR) lseek(fd, (off_t) ct, SEEK_SET); /* skip unused hdr */
return(m);
return(NULL);
}
/*===========================================================================*
* new_mem *
*===========================================================================*/
PRIVATE int new_mem(sh_mp, text_bytes, data_bytes,
PRIVATE int new_mem(rmp, sh_mp, text_bytes, data_bytes,
bss_bytes,stk_bytes,tot_bytes)
struct mproc *rmp; /* process to get a new memory map */
struct mproc *sh_mp; /* text can be shared with this process */
vir_bytes text_bytes; /* text segment size in bytes */
vir_bytes data_bytes; /* size of initialized data in bytes */
@ -303,7 +282,6 @@ phys_bytes tot_bytes; /* total memory to allocate, including gap */
* the new map to the kernel. Zero the new core image's bss, gap and stack.
*/
register struct mproc *rmp = mp;
vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks;
phys_clicks new_base;
phys_bytes bytes, base, bss_offset;
@ -333,8 +311,6 @@ phys_bytes tot_bytes; /* total memory to allocate, including gap */
if (new_base == NO_MEM) return(ENOMEM);
/* We've got memory for the new core image. Release the old one. */
rmp = mp;
if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
/* No other process shares the text segment, so free it. */
free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
@ -354,6 +330,16 @@ phys_bytes tot_bytes; /* total memory to allocate, including gap */
rmp->mp_seg[T].mem_phys = new_base;
rmp->mp_seg[T].mem_vir = 0;
rmp->mp_seg[T].mem_len = text_clicks;
if (text_clicks > 0)
{
/* Zero the last click of the text segment. Otherwise the
* part of that click may remain unchanged.
*/
base = (phys_bytes)(new_base+text_clicks-1) << CLICK_SHIFT;
if ((s= sys_memset(0, base, CLICK_SIZE)) != OK)
panic(__FILE__, "new_mem: sys_memset failed", s);
}
}
rmp->mp_seg[D].mem_phys = new_base + text_clicks;
rmp->mp_seg[D].mem_vir = 0;
@ -369,7 +355,7 @@ phys_bytes tot_bytes; /* total memory to allocate, including gap */
+ rmp->mp_seg[D].mem_len + gap_clicks;
#endif
if((r2=sys_newmap(who_e, rmp->mp_seg)) != OK) {
if((r2=sys_newmap(rmp->mp_endpoint, rmp->mp_seg)) != OK) {
/* report new map to the kernel */
panic(__FILE__,"sys_newmap failed", r2);
}
@ -390,215 +376,3 @@ phys_bytes tot_bytes; /* total memory to allocate, including gap */
return(OK);
}
/*===========================================================================*
* patch_ptr *
*===========================================================================*/
PRIVATE void patch_ptr(stack, base)
char stack[ARG_MAX]; /* pointer to stack image within PM */
vir_bytes base; /* virtual address of stack base inside user */
{
/* When doing an exec(name, argv, envp) call, the user builds up a stack
* image with arg and env pointers relative to the start of the stack. Now
* these pointers must be relocated, since the stack is not positioned at
* address 0 in the user's address space.
*/
char **ap, flag;
vir_bytes v;
flag = 0; /* counts number of 0-pointers seen */
ap = (char **) stack; /* points initially to 'nargs' */
ap++; /* now points to argv[0] */
while (flag < 2) {
if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
if (*ap != NULL) {
v = (vir_bytes) *ap; /* v is relative pointer */
v += base; /* relocate it */
*ap = (char *) v; /* put it back */
} else {
flag++;
}
ap++;
}
}
/*===========================================================================*
* insert_arg *
*===========================================================================*/
PRIVATE int insert_arg(stack, stk_bytes, arg, replace)
char stack[ARG_MAX]; /* pointer to stack image within PM */
vir_bytes *stk_bytes; /* size of initial stack */
char *arg; /* argument to prepend/replace as new argv[0] */
int replace;
{
/* Patch the stack so that arg will become argv[0]. Be careful, the stack may
* be filled with garbage, although it normally looks like this:
* nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
* followed by the strings "pointed" to by the argv[i] and the envp[i]. The
* pointers are really offsets from the start of stack.
* Return true iff the operation succeeded.
*/
int offset, a0, a1, old_bytes = *stk_bytes;
/* Prepending arg adds at least one string and a zero byte. */
offset = strlen(arg) + 1;
a0 = (int) ((char **) stack)[1]; /* argv[0] */
if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE);
a1 = a0; /* a1 will point to the strings to be moved */
if (replace) {
/* Move a1 to the end of argv[0][] (argv[1] if nargs > 1). */
do {
if (a1 == old_bytes) return(FALSE);
--offset;
} while (stack[a1++] != 0);
} else {
offset += PTRSIZE; /* new argv[0] needs new pointer in argv[] */
a0 += PTRSIZE; /* location of new argv[0][]. */
}
/* stack will grow by offset bytes (or shrink by -offset bytes) */
if ((*stk_bytes += offset) > ARG_MAX) return(FALSE);
/* Reposition the strings by offset bytes */
memmove(stack + a1 + offset, stack + a1, old_bytes - a1);
strcpy(stack + a0, arg); /* Put arg in the new space. */
if (!replace) {
/* Make space for a new argv[0]. */
memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE);
((char **) stack)[0]++; /* nargs++; */
}
/* Now patch up argv[] and envp[] by offset. */
patch_ptr(stack, (vir_bytes) offset);
((char **) stack)[1] = (char *) a0; /* set argv[0] correctly */
return(TRUE);
}
/*===========================================================================*
* patch_stack *
*===========================================================================*/
PRIVATE char *patch_stack(fd, stack, stk_bytes, script)
int fd; /* file descriptor to open script file */
char stack[ARG_MAX]; /* pointer to stack image within PM */
vir_bytes *stk_bytes; /* size of initial stack */
char *script; /* name of script to interpret */
{
/* Patch the argument vector to include the path name of the script to be
* interpreted, and all strings on the #! line. Returns the path name of
* the interpreter.
*/
char *sp, *interp = NULL;
int n;
enum { INSERT=FALSE, REPLACE=TRUE };
/* Make script[] the new argv[0]. */
if (!insert_arg(stack, stk_bytes, script, REPLACE)) return(NULL);
if (lseek(fd, 2L, 0) == -1 /* just behind the #! */
|| (n= read(fd, script, PATH_MAX)) < 0 /* read line one */
|| (sp= memchr(script, '\n', n)) == NULL) /* must be a proper line */
return(NULL);
/* Move sp backwards through script[], prepending each string to stack. */
for (;;) {
/* skip spaces behind argument. */
while (sp > script && (*--sp == ' ' || *sp == '\t')) {}
if (sp == script) break;
sp[1] = 0;
/* Move to the start of the argument. */
while (sp > script && sp[-1] != ' ' && sp[-1] != '\t') --sp;
interp = sp;
if (!insert_arg(stack, stk_bytes, sp, INSERT)) return(NULL);
}
/* Round *stk_bytes up to the size of a pointer for alignment contraints. */
*stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE;
close(fd);
return(interp);
}
/*===========================================================================*
* rw_seg *
*===========================================================================*/
PUBLIC void rw_seg(rw, fd, proc_e, seg, seg_bytes0)
int rw; /* 0 = read, 1 = write */
int fd; /* file descriptor to read from / write to */
int proc_e; /* process number (endpoint) */
int seg; /* T, D, or S */
phys_bytes seg_bytes0; /* how much is to be transferred? */
{
/* Transfer text or data from/to a file and copy to/from a process segment.
* This procedure is a little bit tricky. The logical way to transfer a
* segment would be block by block and copying each block to/from the user
* space one at a time. This is too slow, so we do something dirty here,
* namely send the user space and virtual address to the file system in the
* upper 10 bits of the file descriptor, and pass it the user virtual address
* instead of a PM address. The file system extracts these parameters when
* gets a read or write call from the process manager, which is the only
* process that is permitted to use this trick. The file system then copies
* the whole segment directly to/from user space, bypassing PM completely.
*
* The byte count on read is usually smaller than the segment count, because
* a segment is padded out to a click multiple, and the data segment is only
* partially initialized.
*/
int bytes, r, proc_n;
char *ubuf_ptr;
struct mem_map *sp;
phys_bytes seg_bytes = seg_bytes0;
if(pm_isokendpt(proc_e, &proc_n) != OK || proc_n < 0)
return;
sp = &mproc[proc_n].mp_seg[seg];
ubuf_ptr = (char *) ((vir_bytes) sp->mem_vir << CLICK_SHIFT);
while (seg_bytes != 0) {
#define PM_CHUNK_SIZE 8192
bytes = MIN((INT_MAX / PM_CHUNK_SIZE) * PM_CHUNK_SIZE, seg_bytes);
if(!rw) {
r = _read_pm(fd, ubuf_ptr, bytes, seg, proc_e);
} else {
r = _write_pm(fd, ubuf_ptr, bytes, seg, proc_e);
}
if (r != bytes) break;
ubuf_ptr += bytes;
seg_bytes -= bytes;
}
}
/*===========================================================================*
* find_share *
*===========================================================================*/
PUBLIC struct mproc *find_share(mp_ign, ino, dev, ctime)
struct mproc *mp_ign; /* process that should not be looked at */
ino_t ino; /* parameters that uniquely identify a file */
dev_t dev;
time_t ctime;
{
/* Look for a process that is the file <ino, dev, ctime> in execution. Don't
* accidentally "find" mp_ign, because it is the process on whose behalf this
* call is made.
*/
struct mproc *sh_mp;
for (sh_mp = &mproc[0]; sh_mp < &mproc[NR_PROCS]; sh_mp++) {
if (!(sh_mp->mp_flags & SEPARATE)) continue;
if (sh_mp == mp_ign) continue;
if (sh_mp->mp_ino != ino) continue;
if (sh_mp->mp_dev != dev) continue;
if (sh_mp->mp_ctime != ctime) continue;
return sh_mp;
}
return(NULL);
}

View file

@ -11,6 +11,7 @@
* do_pm_exit: perform the EXIT system call (by calling pm_exit())
* pm_exit: actually do the exiting
* do_wait: perform the WAITPID or WAIT system call
* tell_parent: tell parent about the death of a child
*/
#include "pm.h"
@ -103,21 +104,117 @@ PUBLIC int do_fork()
rmc->mp_pid = new_pid; /* assign pid to child */
/* Tell kernel and file system about the (now successful) FORK. */
if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint)) != OK) {
if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint, rmc->mp_seg)) != OK) {
panic(__FILE__,"do_fork can't sys_fork", r);
}
tell_fs(FORK, who_e, rmc->mp_endpoint, rmc->mp_pid);
/* Report child's memory map to kernel. */
if((r=sys_newmap(rmc->mp_endpoint, rmc->mp_seg)) != OK) {
panic(__FILE__,"do_fork can't sys_newmap", r);
if (rmc->mp_fs_call != PM_IDLE)
panic("pm", "do_fork: not idle", rmc->mp_fs_call);
rmc->mp_fs_call= PM_FORK;
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "do_fork: unable to notify FS", r);
/* Do not reply until FS is ready to process the fork
* request
*/
return SUSPEND;
}
/*===========================================================================*
* do_fork_nb *
*===========================================================================*/
PUBLIC int do_fork_nb()
{
/* The process pointed to by 'mp' has forked. Create a child process. */
register struct mproc *rmp; /* pointer to parent */
register struct mproc *rmc; /* pointer to child */
int child_nr, s;
phys_clicks prog_clicks, child_base;
phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
pid_t new_pid;
static int next_child;
int n = 0, r;
/* Only system processes are allowed to use fork_nb */
if (!(mp->mp_flags & PRIV_PROC))
return EPERM;
/* If tables might fill up during FORK, don't even start since recovery half
* way through is such a nuisance.
*/
rmp = mp;
if ((procs_in_use == NR_PROCS) ||
(procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
{
printf("PM: warning, process table is full!\n");
return(EAGAIN);
}
/* Reply to child to wake it up. */
setreply(child_nr, 0); /* only parent gets details */
rmp->mp_reply.endpt = rmc->mp_endpoint; /* child's process number */
/* Determine how much memory to allocate. Only the data and stack need to
* be copied, because the text segment is either shared or of zero length.
*/
prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
return(new_pid); /* child's pid */
/* Create a copy of the parent's core image for the child. */
child_abs = (phys_bytes) child_base << CLICK_SHIFT;
parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
s = sys_abscopy(parent_abs, child_abs, prog_bytes);
if (s < 0) panic(__FILE__,"do_fork can't copy", s);
/* Find a slot in 'mproc' for the child process. A slot must exist. */
do {
next_child = (next_child+1) % NR_PROCS;
n++;
} while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
if(n > NR_PROCS)
panic(__FILE__,"do_fork can't find child slot", NO_NUM);
if(next_child < 0 || next_child >= NR_PROCS
|| (mproc[next_child].mp_flags & IN_USE))
panic(__FILE__,"do_fork finds wrong child slot", next_child);
rmc = &mproc[next_child];
/* Set up the child and its memory map; copy its 'mproc' slot from parent. */
child_nr = (int)(rmc - mproc); /* slot number of the child */
procs_in_use++;
*rmc = *rmp; /* copy parent's process slot to child's */
rmc->mp_parent = who_p; /* record child's parent */
/* inherit only these flags */
rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP);
rmc->mp_child_utime = 0; /* reset administration */
rmc->mp_child_stime = 0; /* reset administration */
/* A separate I&D child keeps the parents text segment. The data and stack
* segments must refer to the new copy.
*/
if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;
rmc->mp_seg[D].mem_phys = child_base;
rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys +
(rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
rmc->mp_exitstatus = 0;
rmc->mp_sigstatus = 0;
/* Find a free pid for the child and put it in the table. */
new_pid = get_free_pid();
rmc->mp_pid = new_pid; /* assign pid to child */
/* Tell kernel and file system about the (now successful) FORK. */
if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint, rmc->mp_seg)) != OK) {
panic(__FILE__,"do_fork can't sys_fork", r);
}
if (rmc->mp_fs_call != PM_IDLE)
panic("pm", "do_fork: not idle", rmc->mp_fs_call);
rmc->mp_fs_call= PM_FORK_NB;
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "do_fork: unable to notify FS", r);
/* Wakeup the newly created process */
setreply(rmc-mproc, OK);
return rmc->mp_pid;
}
/*===========================================================================*
@ -128,16 +225,17 @@ PUBLIC int do_pm_exit()
/* Perform the exit(status) system call. The real work is done by pm_exit(),
* which is also called when a process is killed by a signal.
*/
pm_exit(mp, m_in.status);
pm_exit(mp, m_in.status, FALSE /*!for_trace*/);
return(SUSPEND); /* can't communicate from beyond the grave */
}
/*===========================================================================*
* pm_exit *
*===========================================================================*/
PUBLIC void pm_exit(rmp, exit_status)
PUBLIC void pm_exit(rmp, exit_status, for_trace)
register struct mproc *rmp; /* pointer to the process to be terminated */
int exit_status; /* the process' exit status (for parent) */
int for_trace;
{
/* A process is done. Release most of the process' possessions. If its
* parent is waiting, release the rest, else keep the process slot and
@ -173,38 +271,51 @@ int exit_status; /* the process' exit status (for parent) */
* such as copying to/ from the exiting process, before it is gone.
*/
sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */
if(proc_nr_e != FS_PROC_NR) /* if it is not FS that is exiting.. */
tell_fs(EXIT, proc_nr_e, 0, 0); /* tell FS to free the slot */
if (proc_nr_e == INIT_PROC_NR)
{
printf("PM: INIT died\n");
return;
}
else
if(proc_nr_e != FS_PROC_NR) /* if it is not FS that is exiting.. */
{
/* Tell FS about the exiting process. */
if (rmp->mp_fs_call != PM_IDLE)
panic(__FILE__, "pm_exit: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= (for_trace ? PM_EXIT_TR : PM_EXIT);
r= notify(FS_PROC_NR);
if (r != OK) panic(__FILE__, "pm_exit: unable to notify FS", r);
if (rmp->mp_flags & PRIV_PROC)
{
/* destroy system processes without waiting for FS */
if((r= sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "pm_exit: sys_exit failed", r);
}
}
else
{
printf("PM: FS died\n");
if((r=sys_exit(proc_nr_e)) != OK) /* destroy the process */
panic(__FILE__,"pm_exit: sys_exit failed", r);
return;
}
/* Pending reply messages for the dead process cannot be delivered. */
rmp->mp_flags &= ~REPLY;
/* Keep the process around until FS is finished with it. */
/* Release the memory occupied by the child. */
if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
/* No other process shares the text segment, so free it. */
free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
}
/* Free the data and stack segments. */
free_mem(rmp->mp_seg[D].mem_phys,
rmp->mp_seg[S].mem_vir
+ rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
/* The process slot can only be freed if the parent has done a WAIT. */
rmp->mp_exitstatus = (char) exit_status;
pidarg = p_mp->mp_wpid; /* who's being waited for? */
parent_waiting = p_mp->mp_flags & WAITING;
right_child = /* child meets one of the 3 tests? */
(pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
if (parent_waiting && right_child) {
cleanup(rmp); /* tell parent and release child slot */
tell_parent(rmp); /* tell parent */
} else {
rmp->mp_flags = IN_USE|ZOMBIE; /* parent not waiting, zombify child */
rmp->mp_flags &= (IN_USE|PRIV_PROC);
rmp->mp_flags |= ZOMBIE; /* parent not waiting, zombify child */
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
}
@ -214,7 +325,8 @@ int exit_status; /* the process' exit status (for parent) */
/* 'rmp' now points to a child to be disinherited. */
rmp->mp_parent = INIT_PROC_NR;
parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
if (parent_waiting && (rmp->mp_flags & ZOMBIE)) cleanup(rmp);
if (parent_waiting && (rmp->mp_flags & ZOMBIE))
cleanup(rmp);
}
}
@ -259,7 +371,9 @@ PUBLIC int do_waitpid()
children++; /* this child is acceptable */
if (rp->mp_flags & ZOMBIE) {
/* This child meets the pid test and has exited. */
cleanup(rp); /* this child has already exited */
tell_parent(rp); /* this child has already exited */
if (rp->mp_fs_call == PM_IDLE)
real_cleanup(rp);
return(SUSPEND);
}
if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
@ -293,20 +407,47 @@ register struct mproc *child; /* tells which process is exiting */
/* Finish off the exit of a process. The process has exited or been killed
* by a signal, and its parent is waiting.
*/
struct mproc *parent = &mproc[child->mp_parent];
int exitstatus;
if (child->mp_fs_call != PM_IDLE)
panic(__FILE__, "cleanup: not idle", child->mp_fs_call);
tell_parent(child);
real_cleanup(child);
}
/*===========================================================================*
* tell_parent *
*===========================================================================*/
PUBLIC void tell_parent(child)
register struct mproc *child; /* tells which process is exiting */
{
int exitstatus, mp_parent;
struct mproc *parent;
mp_parent= child->mp_parent;
if (mp_parent <= 0)
panic(__FILE__, "tell_parent: bad value in mp_parent", mp_parent);
parent = &mproc[mp_parent];
/* Wake up the parent by sending the reply message. */
exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
parent->mp_reply.reply_res2 = exitstatus;
setreply(child->mp_parent, child->mp_pid);
parent->mp_flags &= ~WAITING; /* parent no longer waiting */
/* Release the process table entry and reinitialize some field. */
child->mp_pid = 0;
child->mp_flags = 0;
child->mp_child_utime = 0;
child->mp_child_stime = 0;
procs_in_use--;
child->mp_flags &= ~ZOMBIE; /* avoid informing parent twice */
}
/*===========================================================================*
* real_cleanup *
*===========================================================================*/
PUBLIC void real_cleanup(rmp)
register struct mproc *rmp; /* tells which process is exiting */
{
/* Release the process table entry and reinitialize some field. */
rmp->mp_pid = 0;
rmp->mp_flags = 0;
rmp->mp_child_utime = 0;
rmp->mp_child_stime = 0;
procs_in_use--;
}

View file

@ -50,8 +50,21 @@ PUBLIC int do_getset()
return(EPERM);
if(call_nr == SETUID) rmp->mp_realuid = (uid_t) m_in.usr_id;
rmp->mp_effuid = (uid_t) m_in.usr_id;
tell_fs(SETUID, who_e, rmp->mp_realuid, rmp->mp_effuid);
r = OK;
if (rmp->mp_fs_call != PM_IDLE)
{
panic(__FILE__, "do_getset: not idle",
rmp->mp_fs_call);
}
rmp->mp_fs_call= PM_SETUID;
r= notify(FS_PROC_NR);
if (r != OK)
panic(__FILE__, "do_getset: unable to notify FS", r);
/* Do not reply until FS is ready to process the setuid
* request
*/
r= SUSPEND;
break;
case SETEGID:
@ -61,15 +74,42 @@ PUBLIC int do_getset()
return(EPERM);
if(call_nr == SETGID) rmp->mp_realgid = (gid_t) m_in.grp_id;
rmp->mp_effgid = (gid_t) m_in.grp_id;
tell_fs(SETGID, who_e, rmp->mp_realgid, rmp->mp_effgid);
r = OK;
if (rmp->mp_fs_call != PM_IDLE)
{
panic(__FILE__, "do_getset: not idle",
rmp->mp_fs_call);
}
rmp->mp_fs_call= PM_SETGID;
r= notify(FS_PROC_NR);
if (r != OK)
panic(__FILE__, "do_getset: unable to notify FS", r);
/* Do not reply until FS is ready to process the setgid
* request
*/
r= SUSPEND;
break;
case SETSID:
if (rmp->mp_procgrp == rmp->mp_pid) return(EPERM);
rmp->mp_procgrp = rmp->mp_pid;
tell_fs(SETSID, who_e, 0, 0);
/* fall through */
if (rmp->mp_fs_call != PM_IDLE)
{
panic(__FILE__, "do_getset: not idle",
rmp->mp_fs_call);
}
rmp->mp_fs_call= PM_SETSID;
r= notify(FS_PROC_NR);
if (r != OK)
panic(__FILE__, "do_getset: unable to notify FS", r);
/* Do not reply until FS is ready to process the setsid
* request
*/
r= SUSPEND;
break;
case GETPGRP:
r = rmp->mp_procgrp;

View file

@ -20,3 +20,11 @@ extern char core_name[]; /* file name where core images are produced */
EXTERN sigset_t core_sset; /* which signals cause core images */
EXTERN sigset_t ign_sset; /* which signals are by default ignored */
EXTERN time_t boottime; /* time when the system was booted (for
* reporting to FS)
*/
EXTERN int report_reboot; /* During reboot to report to FS that we are
* rebooting.
*/
EXTERN int abort_flag;
EXTERN char monitor_code[256];

View file

@ -34,6 +34,8 @@ FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks) );
FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks,
struct mem_map *map_ptr) );
FORWARD _PROTOTYPE( void do_x86_vm, (struct memory mem_chunks[NR_MEMS]) );
FORWARD _PROTOTYPE( void send_work, (void) );
FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
#define click_to_round_k(n) \
((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
@ -55,21 +57,51 @@ PUBLIC int main()
get_work(); /* wait for an PM system call */
/* Check for system notifications first. Special cases. */
if (call_nr == SYN_ALARM) {
switch(call_nr)
{
case SYN_ALARM:
pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
result = SUSPEND; /* don't reply */
} else if (call_nr == SYS_SIG) { /* signals pending */
break;
case SYS_SIG: /* signals pending */
sigset = m_in.NOTIFY_ARG;
if (sigismember(&sigset, SIGKSIG)) {
(void) ksig_pending();
}
result = SUSPEND; /* don't reply */
}
/* Else, if the system call number is valid, perform the call. */
else if ((unsigned) call_nr >= NCALLS) {
result = ENOSYS;
} else {
result = (*call_vec[call_nr])();
break;
case PM_GET_WORK:
if (who_e == FS_PROC_NR)
{
send_work();
result= SUSPEND; /* don't reply */
}
else
result= ENOSYS;
break;
case PM_EXIT_REPLY:
case PM_REBOOT_REPLY:
case PM_EXEC_REPLY:
case PM_CORE_REPLY:
case PM_EXIT_REPLY_TR:
if (who_e == FS_PROC_NR)
{
handle_fs_reply(&m_in);
result= SUSPEND; /* don't reply */
}
else
result= ENOSYS;
break;
default:
/* Else, if the system call number is valid, perform the
* call.
*/
if ((unsigned) call_nr >= NCALLS) {
result = ENOSYS;
} else {
result = (*call_vec[call_nr])();
}
break;
}
/* Send the results back to the user to indicate completion. */
@ -182,6 +214,8 @@ PRIVATE void pm_init()
/* Initialize process table, including timers. */
for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
tmr_inittimer(&rmp->mp_timer);
rmp->mp_fs_call= PM_IDLE;
}
/* Build the set of signals which cause core dumps, and the set of signals
@ -470,3 +504,379 @@ struct memory mem_chunks[NR_MEMS];
if (r != 0)
printf("do_x86_vm: sys_vm_setbuf failed: %d\n", r);
}
/*=========================================================================*
* send_work *
*=========================================================================*/
PRIVATE void send_work()
{
int r, call;
struct mproc *rmp;
message m;
m.m_type= PM_IDLE;
for (rmp= mproc; rmp < &mproc[NR_PROCS]; rmp++)
{
call= rmp->mp_fs_call;
if (call == PM_IDLE)
continue;
switch(call)
{
case PM_STIME:
m.m_type= call;
m.PM_STIME_TIME= boottime;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
/* Wakeup the original caller */
setreply(rmp-mproc, OK);
break;
case PM_SETSID:
m.m_type= call;
m.PM_SETSID_PROC= rmp->mp_endpoint;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
/* Wakeup the original caller */
setreply(rmp-mproc, rmp->mp_procgrp);
break;
case PM_SETGID:
m.m_type= call;
m.PM_SETGID_PROC= rmp->mp_endpoint;
m.PM_SETGID_EGID= rmp->mp_effgid;
m.PM_SETGID_RGID= rmp->mp_realgid;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
/* Wakeup the original caller */
setreply(rmp-mproc, OK);
break;
case PM_SETUID:
m.m_type= call;
m.PM_SETUID_PROC= rmp->mp_endpoint;
m.PM_SETUID_EGID= rmp->mp_effuid;
m.PM_SETUID_RGID= rmp->mp_realuid;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
/* Wakeup the original caller */
setreply(rmp-mproc, OK);
break;
case PM_FORK:
{
int parent_e, parent_p;
struct mproc *parent_mp;
parent_p = rmp->mp_parent;
parent_mp = &mproc[parent_p];
m.m_type= call;
m.PM_FORK_PPROC= parent_mp->mp_endpoint;
m.PM_FORK_CPROC= rmp->mp_endpoint;
m.PM_FORK_CPID= rmp->mp_pid;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
/* Wakeup the newly created process */
setreply(rmp-mproc, OK);
/* Wakeup the parent */
setreply(parent_mp-mproc, rmp->mp_pid);
break;
}
case PM_EXIT:
case PM_EXIT_TR:
m.m_type= call;
m.PM_EXIT_PROC= rmp->mp_endpoint;
/* Mark the process as busy */
rmp->mp_fs_call= PM_BUSY;
break;
case PM_UNPAUSE:
case PM_UNPAUSE_TR:
m.m_type= call;
m.PM_UNPAUSE_PROC= rmp->mp_endpoint;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
if (call == PM_UNPAUSE)
{
/* Ask the kernel to deliver the signal */
r= sys_sigsend(rmp->mp_endpoint,
&rmp->mp_sigmsg);
if (r != OK)
panic(__FILE__,"sys_sigsend failed",r);
}
break;
case PM_EXEC:
m.m_type= call;
m.PM_EXEC_PROC= rmp->mp_endpoint;
m.PM_EXEC_PATH= rmp->mp_exec_path;
m.PM_EXEC_PATH_LEN= rmp->mp_exec_path_len;
m.PM_EXEC_FRAME= rmp->mp_exec_frame;
m.PM_EXEC_FRAME_LEN= rmp->mp_exec_frame_len;
/* Mark the process as busy */
rmp->mp_fs_call= PM_BUSY;
break;
case PM_FORK_NB:
{
int parent_e, parent_p;
struct mproc *parent_mp;
parent_p = rmp->mp_parent;
parent_mp = &mproc[parent_p];
m.m_type= PM_FORK;
m.PM_FORK_PPROC= parent_mp->mp_endpoint;
m.PM_FORK_CPROC= rmp->mp_endpoint;
m.PM_FORK_CPID= rmp->mp_pid;
/* FS does not reply */
rmp->mp_fs_call= PM_IDLE;
break;
}
case PM_DUMPCORE:
m.m_type= call;
m.PM_CORE_PROC= rmp->mp_endpoint;
m.PM_CORE_SEGPTR= (char *)rmp->mp_seg;
/* Mark the process as busy */
rmp->mp_fs_call= PM_BUSY;
break;
default:
printf("send_work: should report call 0x%x to FS\n",
call);
break;
}
break;
}
if (m.m_type != PM_IDLE)
{
if (rmp->mp_fs_call == PM_IDLE &&
(rmp->mp_flags & PM_SIG_PENDING))
{
rmp->mp_flags &= ~PM_SIG_PENDING;
check_pending(rmp);
if (!(rmp->mp_flags & PM_SIG_PENDING))
{
/* Allow the process to be scheduled */
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
}
}
}
else if (report_reboot)
{
m.m_type= PM_REBOOT;
report_reboot= FALSE;
}
r= send(FS_PROC_NR, &m);
if (r != OK) panic("pm", "send_work: send failed", r);
}
PRIVATE void handle_fs_reply(m_ptr)
message *m_ptr;
{
int r, proc_e, proc_n;
struct mproc *rmp;
switch(m_ptr->m_type)
{
case PM_EXIT_REPLY:
case PM_EXIT_REPLY_TR:
proc_e= m_ptr->PM_EXIT_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
panic(__FILE__,
"PM_EXIT_REPLY: got bad endpoint from FS",
proc_e);
}
rmp= &mproc[proc_n];
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
if (!(rmp->mp_flags & PRIV_PROC))
{
/* destroy the (user) process */
if((r=sys_exit(proc_e)) != OK)
{
panic(__FILE__,
"PM_EXIT_REPLY: sys_exit failed", r);
}
}
/* Release the memory occupied by the child. */
if (find_share(rmp, rmp->mp_ino, rmp->mp_dev,
rmp->mp_ctime) == NULL) {
/* No other process shares the text segment,
* so free it.
*/
free_mem(rmp->mp_seg[T].mem_phys,
rmp->mp_seg[T].mem_len);
}
/* Free the data and stack segments. */
free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir +
rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
if (m_ptr->m_type == PM_EXIT_REPLY_TR &&
rmp->mp_parent != INIT_PROC_NR)
{
/* Wake up the parent */
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
setreply(rmp->mp_parent, OK);
}
/* Clean up if the parent has collected the exit
* status
*/
if (!(rmp->mp_flags & ZOMBIE))
real_cleanup(rmp);
break;
case PM_REBOOT_REPLY:
{
vir_bytes code_addr;
size_t code_size;
/* Ask the kernel to abort. All system services, including
* the PM, will get a HARD_STOP notification. Await the
* notification in the main loop.
*/
code_addr = (vir_bytes) monitor_code;
code_size = strlen(monitor_code) + 1;
sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
break;
}
case PM_EXEC_REPLY:
proc_e= m_ptr->PM_EXEC_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
panic(__FILE__,
"PM_EXIT_REPLY: got bad endpoint from FS",
proc_e);
}
rmp= &mproc[proc_n];
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
if (rmp->mp_flags & PM_SIG_PENDING)
{
printf("handle_fs_reply: restarting signals\n");
rmp->mp_flags &= ~PM_SIG_PENDING;
check_pending(rmp);
if (!(rmp->mp_flags & PM_SIG_PENDING))
{
printf("handle_fs_reply: calling sys_nice\n");
/* Allow the process to be scheduled */
sys_nice(rmp->mp_endpoint, rmp->mp_nice);
}
else
printf("handle_fs_reply: more signals\n");
}
break;
case PM_CORE_REPLY:
{
int parent_waiting, right_child;
pid_t pidarg;
struct mproc *p_mp;
proc_e= m_ptr->PM_CORE_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
panic(__FILE__,
"PM_EXIT_REPLY: got bad endpoint from FS",
proc_e);
}
rmp= &mproc[proc_n];
if (m_ptr->PM_CORE_STATUS == OK)
rmp->mp_sigstatus |= DUMPED;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
pidarg = p_mp->mp_wpid; /* who's being waited for? */
parent_waiting = p_mp->mp_flags & WAITING;
right_child = /* child meets one of the 3 tests? */
(pidarg == -1 || pidarg == rmp->mp_pid ||
-pidarg == rmp->mp_procgrp);
if (parent_waiting && right_child) {
tell_parent(rmp); /* tell parent */
} else {
/* parent not waiting, zombify child */
rmp->mp_flags &= (IN_USE|PRIV_PROC);
rmp->mp_flags |= ZOMBIE;
/* send parent a "child died" signal */
sig_proc(p_mp, SIGCHLD);
}
if (!(rmp->mp_flags & PRIV_PROC))
{
/* destroy the (user) process */
if((r=sys_exit(proc_e)) != OK)
{
panic(__FILE__,
"PM_CORE_REPLY: sys_exit failed", r);
}
}
/* Release the memory occupied by the child. */
if (find_share(rmp, rmp->mp_ino, rmp->mp_dev,
rmp->mp_ctime) == NULL) {
/* No other process shares the text segment,
* so free it.
*/
free_mem(rmp->mp_seg[T].mem_phys,
rmp->mp_seg[T].mem_len);
}
/* Free the data and stack segments. */
free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir +
rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
/* Clean up if the parent has collected the exit
* status
*/
if (!(rmp->mp_flags & ZOMBIE))
real_cleanup(rmp);
break;
}
default:
panic(__FILE__, "handle_fs_reply: unknown reply type",
m_ptr->m_type);
break;
}
}

View file

@ -179,10 +179,7 @@ PUBLIC int do_getprocnr()
*===========================================================================*/
PUBLIC int do_reboot()
{
char monitor_code[256];
vir_bytes code_addr;
int code_size;
int abort_flag;
int r;
/* Check permission to abort the system. */
if (mp->mp_effuid != SUPER_USER) return(EPERM);
@ -197,10 +194,10 @@ PUBLIC int do_reboot()
if((r = sys_datacopy(who_e, (vir_bytes) m_in.reboot_code,
SELF, (vir_bytes) monitor_code, m_in.reboot_strlen)) != OK)
return r;
code_addr = (vir_bytes) monitor_code;
monitor_code[m_in.reboot_strlen] = '\0';
code_size = m_in.reboot_strlen + 1;
}
else
monitor_code[0] = '\0';
/* Order matters here. When FS is told to reboot, it exits all its
* processes, and then would be confused if they're exited again by
@ -209,12 +206,11 @@ PUBLIC int do_reboot()
check_sig(-1, SIGKILL); /* kill all users except init */
sys_nice(INIT_PROC_NR, PRIO_STOP); /* stop init, but keep it around */
tell_fs(REBOOT, 0, 0, 0); /* tell FS to synchronize */
/* Ask the kernel to abort. All system services, including the PM, will
* get a HARD_STOP notification. Await the notification in the main loop.
*/
sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
report_reboot= 1;
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "do_reboot: unable to notify FS", r);
return(SUSPEND); /* don't reply to caller */
}
@ -386,44 +382,3 @@ PUBLIC int do_svrctl()
return(EINVAL);
}
}
/*===========================================================================*
* _read_pm *
*===========================================================================*/
PUBLIC ssize_t _read_pm(fd, buffer, nbytes, seg, ep)
int fd;
void *buffer;
size_t nbytes;
int seg;
int ep;
{
message m;
m.m1_i1 = _PM_SEG_FLAG | fd;
m.m1_i2 = nbytes;
m.m1_p1 = (char *) buffer;
m.m1_p2 = (char *) seg;
m.m1_p3 = (char *) ep;
return(_syscall(FS_PROC_NR, READ, &m));
}
/*===========================================================================*
* _write_pm *
*===========================================================================*/
PUBLIC ssize_t _write_pm(fd, buffer, nbytes, seg, ep)
int fd;
void *buffer;
size_t nbytes;
int seg;
int ep;
{
message m;
m.m1_i1 = _PM_SEG_FLAG | fd;
m.m1_i2 = nbytes;
m.m1_p1 = (char *) buffer;
m.m1_p2 = (char *) seg;
m.m1_p3 = (char *) ep;
return(_syscall(FS_PROC_NR, WRITE, &m));
}

View file

@ -40,6 +40,9 @@ EXTERN struct mproc {
sigset_t mp_sigpending; /* pending signals to be handled */
struct sigaction mp_sigact[_NSIG + 1]; /* as in sigaction(2) */
vir_bytes mp_sigreturn; /* address of C library __sigreturn function */
struct sigmsg mp_sigmsg; /* Save the details of the signal until the
* PM_UNPAUSE request is delivered.
*/
struct timer mp_timer; /* watchdog timer for alarm(2) */
/* Backwards compatibility for signals. */
@ -50,6 +53,13 @@ EXTERN struct mproc {
struct mproc *mp_swapq; /* queue of procs waiting to be swapped in */
message mp_reply; /* reply message to be sent to one */
/* Communication with FS */
int mp_fs_call;
char *mp_exec_path; /* Path of executable */
vir_bytes mp_exec_path_len; /* Length of path (including nul) */
char *mp_exec_frame; /* Arguments */
vir_bytes mp_exec_frame_len; /* Length of arguments */
/* Scheduling priority. */
signed int mp_nice; /* nice is PRIO_MIN..PRIO_MAX, standard 0. */
@ -71,6 +81,8 @@ EXTERN struct mproc {
#define SWAPIN 0x800 /* set if on the "swap this in" queue */
#define DONT_SWAP 0x1000 /* never swap out this process */
#define PRIV_PROC 0x2000 /* system process, special privileges */
#define PM_SIG_PENDING 0x4000 /* process got a signal while waiting for FS */
#define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */
#define NIL_MPROC ((struct mproc *) 0)

View file

@ -38,16 +38,21 @@ _PROTOTYPE( int do_fkey_pressed, (void) );
/* exec.c */
_PROTOTYPE( int do_exec, (void) );
_PROTOTYPE( void rw_seg, (int rw, int fd, int proc, int seg,
phys_bytes seg_bytes) );
_PROTOTYPE( int exec_newmem, (void) );
_PROTOTYPE( int do_execrestart, (void) );
_PROTOTYPE( void exec_restart, (struct mproc *rmp, int result) );
_PROTOTYPE( struct mproc *find_share, (struct mproc *mp_ign, Ino_t ino,
Dev_t dev, time_t ctime) );
/* forkexit.c */
_PROTOTYPE( int do_fork, (void) );
_PROTOTYPE( int do_fork_nb, (void) );
_PROTOTYPE( int do_pm_exit, (void) );
_PROTOTYPE( int do_waitpid, (void) );
_PROTOTYPE( void pm_exit, (struct mproc *rmp, int exit_status) );
_PROTOTYPE( void pm_exit, (struct mproc *rmp, int exit_status,
int for_trace) );
_PROTOTYPE (void tell_parent, (struct mproc *child) );
_PROTOTYPE( void real_cleanup, (struct mproc *rmp) );
/* getset.c */
_PROTOTYPE( int do_getset, (void) );
@ -63,9 +68,7 @@ _PROTOTYPE( int do_getprocnr, (void) );
_PROTOTYPE( int do_svrctl, (void) );
_PROTOTYPE( int do_allocmem, (void) );
_PROTOTYPE( int do_freemem, (void) );
_PROTOTYPE( int do_getsetpriority, (void) );
_PROTOTYPE( ssize_t _read_pm, (int _fd, void *_buf, size_t _n, int s, int e));
_PROTOTYPE( ssize_t _write_pm, (int _fd, void *_buf, size_t _n, int s, int e));
_PROTOTYPE( int do_getsetpriority, (void) );
#if (MACHINE == MACINTOSH)
@ -107,10 +110,8 @@ _PROTOTYPE( void stop_proc, (struct mproc *rmp, int sig_nr) );
/* utility.c */
_PROTOTYPE( pid_t get_free_pid, (void) );
_PROTOTYPE( int allowed, (char *name_buf, struct stat *s_buf, int mask) );
_PROTOTYPE( int no_sys, (void) );
_PROTOTYPE( void panic, (char *who, char *mess, int num) );
_PROTOTYPE( void tell_fs, (int what, int p1, int p2, int p3) );
_PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp) );
_PROTOTYPE( int get_mem_map, (int proc_nr, struct mem_map *mem_map) );
_PROTOTYPE( char *find_param, (const char *key));

View file

@ -27,16 +27,14 @@
#include <minix/endpoint.h>
#include <minix/com.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/sigcontext.h>
#include <string.h>
#include "mproc.h"
#include "param.h"
#define CORE_MODE 0777 /* mode to use on core image files */
#define DUMPED 0200 /* bit set in status when core dumped */
FORWARD _PROTOTYPE( void dump_core, (struct mproc *rmp) );
FORWARD _PROTOTYPE( void unpause, (int pro) );
FORWARD _PROTOTYPE( int dump_core, (struct mproc *rmp) );
FORWARD _PROTOTYPE( void unpause, (int pro, int for_trace) );
FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp) );
@ -233,8 +231,10 @@ PUBLIC int ksig_pending()
* has been handled ...
*/
if ((mproc[proc_nr_p].mp_flags & (IN_USE | ZOMBIE)) == IN_USE)
{
if((r=sys_endksig(proc_nr_e)) != OK) /* ... tell kernel it's done */
panic(__FILE__,"sys_endksig failed", r);
}
}
}
return(SUSPEND); /* prevents sending reply */
@ -274,10 +274,6 @@ sigset_t sig_map;
case SIGQUIT:
case SIGWINCH:
id = 0; break; /* broadcast to process group */
#if 0
case SIGKILL:
id = -1; break; /* broadcast to all except INIT */
#endif
default:
id = proc_id;
break;
@ -417,7 +413,6 @@ int signo; /* signal to send to process (1 to _NSIG) */
int s;
int slot;
int sigflags;
struct sigmsg sm;
slot = (int) (rmp - mproc);
if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) {
@ -425,9 +420,18 @@ int signo; /* signal to send to process (1 to _NSIG) */
signo, (rmp->mp_flags & ZOMBIE) ? "zombie" : "dead", slot);
panic(__FILE__,"", NO_NUM);
}
if (rmp->mp_fs_call != PM_IDLE)
{
sigaddset(&rmp->mp_sigpending, signo);
rmp->mp_flags |= PM_SIG_PENDING;
/* keep the process from running */
sys_nice(rmp->mp_endpoint, PRIO_STOP);
return;
}
if ((rmp->mp_flags & TRACED) && signo != SIGKILL) {
/* A traced process has special handling. */
unpause(slot);
unpause(slot, TRUE /*for_trace*/);
stop_proc(rmp, signo); /* a signal causes it to stop */
return;
}
@ -451,15 +455,16 @@ int signo; /* signal to send to process (1 to _NSIG) */
sigflags = rmp->mp_sigact[signo].sa_flags;
if (sigismember(&rmp->mp_catch, signo)) {
if (rmp->mp_flags & SIGSUSPENDED)
sm.sm_mask = rmp->mp_sigmask2;
rmp->mp_sigmsg.sm_mask = rmp->mp_sigmask2;
else
sm.sm_mask = rmp->mp_sigmask;
sm.sm_signo = signo;
sm.sm_sighandler = (vir_bytes) rmp->mp_sigact[signo].sa_handler;
sm.sm_sigreturn = rmp->mp_sigreturn;
rmp->mp_sigmsg.sm_mask = rmp->mp_sigmask;
rmp->mp_sigmsg.sm_signo = signo;
rmp->mp_sigmsg.sm_sighandler =
(vir_bytes) rmp->mp_sigact[signo].sa_handler;
rmp->mp_sigmsg.sm_sigreturn = rmp->mp_sigreturn;
if ((s=get_stack_ptr(rmp->mp_endpoint, &new_sp)) != OK)
panic(__FILE__,"couldn't get new stack pointer (for sig)",s);
sm.sm_stkptr = new_sp;
rmp->mp_sigmsg.sm_stkptr = new_sp;
/* Make room for the sigcontext and sigframe struct. */
new_sp -= sizeof(struct sigcontext)
@ -478,17 +483,29 @@ int signo; /* signal to send to process (1 to _NSIG) */
sigdelset(&rmp->mp_catch, signo);
rmp->mp_sigact[signo].sa_handler = SIG_DFL;
}
sigdelset(&rmp->mp_sigpending, signo);
if (OK == (s=sys_sigsend(rmp->mp_endpoint, &sm))) {
/* Check to see if process is hanging on a PAUSE, WAIT or SIGSUSPEND
* call.
*/
if (rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED)) {
rmp->mp_flags &= ~(PAUSED | WAITING | SIGSUSPENDED);
setreply(slot, EINTR);
sigdelset(&rmp->mp_sigpending, signo);
/* If process is hanging on PAUSE, WAIT, SIGSUSPEND, tty,
* pipe, etc., release it.
*/
unpause(slot);
/* Ask the kernel to deliver the signal */
s= sys_sigsend(rmp->mp_endpoint, &rmp->mp_sigmsg);
if (s != OK)
panic(__FILE__, "sys_sigsend failed", s);
/* Done */
return;
}
panic(__FILE__, "sys_sigsend failed", s);
/* Ask FS to unpause the process. Deliver the signal when FS is
* ready.
*/
unpause(slot, FALSE /*!for_trace*/);
return;
}
else if (sigismember(&rmp->mp_sig2mess, signo)) {
@ -512,11 +529,14 @@ doterminate:
return;
}
#endif
/* Switch to the user's FS environment and dump core. */
tell_fs(CHDIR, rmp->mp_endpoint, FALSE, 0);
dump_core(rmp);
s= dump_core(rmp);
if (s == SUSPEND)
return;
/* Not dumping core, just call exit */
}
pm_exit(rmp, 0); /* terminate process */
pm_exit(rmp, 0, FALSE /*!for_trace*/); /* terminate process */
}
/*===========================================================================*
@ -618,8 +638,9 @@ register struct mproc *rmp;
/*===========================================================================*
* unpause *
*===========================================================================*/
PRIVATE void unpause(pro)
PRIVATE void unpause(pro, for_trace)
int pro; /* which process number */
int for_trace; /* for tracing */
{
/* A signal is to be sent to a process. If that process is hanging on a
* system call, the system call must be terminated with EINTR. Possible
@ -627,8 +648,8 @@ int pro; /* which process number */
* First check if the process is hanging on an PM call. If not, tell FS,
* so it can check for READs and WRITEs from pipes, ttys and the like.
*/
register struct mproc *rmp;
int r;
rmp = &mproc[pro];
@ -640,30 +661,29 @@ int pro; /* which process number */
}
/* Process is not hanging on an PM call. Ask FS to take a look. */
tell_fs(UNPAUSE, rmp->mp_endpoint, 0, 0);
if (rmp->mp_fs_call != PM_IDLE)
panic("pm", "unpause: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= (for_trace ? PM_UNPAUSE_TR : PM_UNPAUSE);
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "unpause: unable to notify FS", r);
}
/*===========================================================================*
* dump_core *
*===========================================================================*/
PRIVATE void dump_core(rmp)
PRIVATE int dump_core(rmp)
register struct mproc *rmp; /* whose core is to be dumped */
{
/* Make a core dump on the file "core", if possible. */
int s, fd, seg, slot;
int r, proc_nr, proc_nr_e, parent_waiting;
pid_t procgrp;
vir_bytes current_sp;
long trace_data, trace_off;
struct mproc *p_mp;
clock_t t[5];
slot = (int) (rmp - mproc);
/* Can core file be written? We are operating in the user's FS environment,
* so no special permission checks are needed.
*/
if (rmp->mp_realuid != rmp->mp_effuid) return;
if ( (fd = open(core_name, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK,
CORE_MODE)) < 0) return;
rmp->mp_sigstatus |= DUMPED;
/* Do not create core files for set uid execution */
if (rmp->mp_realuid != rmp->mp_effuid) return OK;
/* Make sure the stack segment is up to date.
* We don't want adjust() to fail unless current_sp is preposterous,
@ -671,33 +691,91 @@ register struct mproc *rmp; /* whose core is to be dumped */
* the adjust() for sending a signal to fail due to safety checking.
* Maybe make SAFETY_BYTES a parameter.
*/
if ((s=get_stack_ptr(rmp->mp_endpoint, &current_sp)) != OK)
panic(__FILE__,"couldn't get new stack pointer (for core)",s);
if ((r= get_stack_ptr(rmp->mp_endpoint, &current_sp)) != OK)
panic(__FILE__,"couldn't get new stack pointer (for core)", r);
adjust(rmp, rmp->mp_seg[D].mem_len, current_sp);
/* Write the memory map of all segments to begin the core file. */
if (write(fd, (char *) rmp->mp_seg, (unsigned) sizeof rmp->mp_seg)
!= (unsigned) sizeof rmp->mp_seg) {
close(fd);
/* Tell FS about the exiting process. */
if (rmp->mp_fs_call != PM_IDLE)
panic(__FILE__, "dump_core: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= PM_DUMPCORE;
r= notify(FS_PROC_NR);
if (r != OK) panic(__FILE__, "dump_core: unable to notify FS", r);
/* Also perform most of the normal exit processing. Informing the parent
* has to wait until we know whether the coredump was successful or not.
*/
proc_nr = (int) (rmp - mproc); /* get process slot number */
proc_nr_e = rmp->mp_endpoint;
/* Remember a session leader's process group. */
procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
/* If the exited process has a timer pending, kill it. */
if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr_e, (unsigned) 0);
/* Do accounting: fetch usage times and accumulate at parent. */
if((r=sys_times(proc_nr_e, t)) != OK)
panic(__FILE__,"pm_exit: sys_times failed", r);
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
p_mp->mp_child_utime += t[0] + rmp->mp_child_utime; /* add user time */
p_mp->mp_child_stime += t[1] + rmp->mp_child_stime; /* add system time */
/* Tell the kernel the process is no longer runnable to prevent it from
* being scheduled in between the following steps. Then tell FS that it
* the process has exited and finally, clean up the process at the kernel.
* This order is important so that FS can tell drivers to cancel requests
* such as copying to/ from the exiting process, before it is gone.
*/
sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */
if(proc_nr_e != FS_PROC_NR) /* if it is not FS that is exiting.. */
{
if (rmp->mp_flags & PRIV_PROC)
{
/* destroy system processes without waiting for FS */
if((r= sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "pm_exit: sys_exit failed", r);
/* Just send a SIGCHLD. Dealing with waidpid is too complicated
* here.
*/
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
sig_proc(p_mp, SIGCHLD);
/* Zombify to avoid calling sys_endksig */
rmp->mp_flags |= ZOMBIE;
}
}
else
{
printf("PM: FS died\n");
return;
}
/* Write out the whole kernel process table entry to get the regs. */
trace_off = 0;
while (sys_trace(T_GETUSER, rmp->mp_endpoint, trace_off, &trace_data) == OK) {
if (write(fd, (char *) &trace_data, (unsigned) sizeof (long))
!= (unsigned) sizeof (long)) {
close(fd);
return;
/* Pending reply messages for the dead process cannot be delivered. */
rmp->mp_flags &= ~REPLY;
/* Keep the process around until FS is finished with it. */
/* If the process has children, disinherit them. INIT is the new parent. */
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
/* 'rmp' now points to a child to be disinherited. */
rmp->mp_parent = INIT_PROC_NR;
parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
if (parent_waiting && (rmp->mp_flags & ZOMBIE))
{
tell_parent(rmp);
real_cleanup(rmp);
}
}
trace_off += sizeof (long);
}
/* Loop through segments and write the segments themselves out. */
for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
rw_seg(1, fd, rmp->mp_endpoint, seg,
(phys_bytes) rmp->mp_seg[seg].mem_len << CLICK_SHIFT);
}
close(fd);
/* Send a hangup to the process' process group if it was a session leader. */
if (procgrp != 0) check_sig(-procgrp, SIGHUP);
return SUSPEND;
}

View file

@ -81,11 +81,11 @@ _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
no_sys, /* 64 = unused */
no_sys, /* 65 = UNPAUSE */
no_sys, /* 66 = unused */
exec_newmem, /* 66 = EXEC_NEWMEM */
no_sys, /* 67 = REVIVE */
no_sys, /* 68 = TASK_REPLY */
no_sys, /* 69 = unused */
no_sys, /* 70 = unused */
do_fork_nb, /* 69 = FORK_NB */
do_execrestart, /* 70 = EXEC_RESTART */
do_sigaction, /* 71 = sigaction */
do_sigsuspend, /* 72 = sigsuspend */
do_sigpending, /* 73 = sigpending */

View file

@ -13,8 +13,6 @@
#include "mproc.h"
#include "param.h"
PRIVATE time_t boottime;
/*===========================================================================*
* do_time *
*===========================================================================*/
@ -55,10 +53,14 @@ PUBLIC int do_stime()
panic(__FILE__,"do_stime couldn't get uptime", s);
boottime = (long) m_in.stime - (uptime/HZ);
/* Also inform FS about the new system time. */
tell_fs(STIME, boottime, 0, 0);
if (mp->mp_fs_call != PM_IDLE)
panic("pm", "do_stime: not idle", mp->mp_fs_call);
mp->mp_fs_call= PM_STIME;
s= notify(FS_PROC_NR);
if (s != OK) panic("pm", "do_stime: unable to notify FS", s);
return(OK);
/* Do not reply until FS is ready to process the stime request */
return(SUSPEND);
}
/*===========================================================================*

View file

@ -55,9 +55,11 @@ PUBLIC int do_trace()
*/
switch (m_in.request) {
case T_EXIT: /* exit */
pm_exit(child, (int) m_in.data);
mp->mp_reply.reply_trace = 0;
return(OK);
pm_exit(child, (int) m_in.data, TRUE /*for_trace*/);
/* Do not reply to the caller until FS has processed the exit
* request.
*/
return SUSPEND;
case T_RESUME:
case T_STEP: /* resume execution */
if (m_in.data < 0 || m_in.data > _NSIG) return(EIO);

View file

@ -6,7 +6,6 @@
* allowed: see if an access is permitted
* no_sys: called for invalid system call numbers
* panic: PM has run aground of a fatal error
* tell_fs: interface to FS
* get_mem_map: get memory map of given process
* get_stack_ptr: get stack pointer of given process
* proc_from_pid: return process pointer from pid number
@ -52,44 +51,6 @@ PUBLIC pid_t get_free_pid()
return(next_pid);
}
/*===========================================================================*
* allowed *
*===========================================================================*/
PUBLIC int allowed(name_buf, s_buf, mask)
char *name_buf; /* pointer to file name to be EXECed */
struct stat *s_buf; /* buffer for doing and returning stat struct*/
int mask; /* R_BIT, W_BIT, or X_BIT */
{
/* Check to see if file can be accessed. Return EACCES or ENOENT if the access
* is prohibited. If it is legal open the file and return a file descriptor.
*/
int fd;
int save_errno;
/* Use the fact that mask for access() is the same as the permissions mask.
* E.g., X_BIT in <minix/const.h> is the same as X_OK in <unistd.h> and
* S_IXOTH in <sys/stat.h>. tell_fs(DO_CHDIR, ...) has set PM's real ids
* to the user's effective ids, so access() works right for setuid programs.
*/
if (access(name_buf, mask) < 0) return(-errno);
/* The file is accessible but might not be readable. Make it readable. */
tell_fs(SETUID, PM_PROC_NR, (int) SUPER_USER, (int) SUPER_USER);
/* Open the file and fstat it. Restore the ids early to handle errors. */
fd = open(name_buf, O_RDONLY | O_NONBLOCK);
save_errno = errno; /* open might fail, e.g. from ENFILE */
tell_fs(SETUID, PM_PROC_NR, (int) mp->mp_effuid, (int) mp->mp_effuid);
if (fd < 0) return(-save_errno);
if (fstat(fd, s_buf) < 0) panic(__FILE__,"allowed: fstat failed", NO_NUM);
/* Only regular files can be executed. */
if (mask == X_BIT && (s_buf->st_mode & I_TYPE) != I_REGULAR) {
close(fd);
return(EACCES);
}
return(fd);
}
/*===========================================================================*
* no_sys *
@ -117,7 +78,6 @@ int num; /* number to go with it */
int s;
/* Switch to primary console and print panic message. */
check_sig(mproc[TTY_PROC_NR].mp_pid, SIGTERM);
printf("PM panic (%s): %s", who, mess);
if (num != NO_NUM) printf(": %d",num);
printf("\n");
@ -126,34 +86,6 @@ int num; /* number to go with it */
sys_exit(SELF);
}
/*===========================================================================*
* tell_fs *
*===========================================================================*/
PUBLIC void tell_fs(what, p1, p2, p3)
int what, p1, p2, p3;
{
/* This routine is only used by PM to inform FS of certain events:
* tell_fs(CHDIR, slot, dir, 0)
* tell_fs(EXEC, proc, 0, 0)
* tell_fs(EXIT, proc, 0, 0)
* tell_fs(FORK, parent, child, pid)
* tell_fs(SETGID, proc, realgid, effgid)
* tell_fs(SETSID, proc, 0, 0)
* tell_fs(SETUID, proc, realuid, effuid)
* tell_fs(UNPAUSE, proc, signr, 0)
* tell_fs(STIME, time, 0, 0)
* Ignore this call if the FS is already dead, e.g. on shutdown.
*/
message m;
if ((mproc[FS_PROC_NR].mp_flags & (IN_USE|ZOMBIE)) != IN_USE)
return;
m.tell_fs_arg1 = p1;
m.tell_fs_arg2 = p2;
m.tell_fs_arg3 = p3;
_taskcall(FS_PROC_NR, what, &m);
}
/*===========================================================================*
* find_param *