aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Benedict Torvalds <torvalds@klaava.Helsinki.FI>1992-06-15 20:04:54 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:04 -0400
commit2d7bd0389f1494040efcddd5a1b651f362bbf2c9 (patch)
treebeffbf6d95378739fe8ea8dfac77cd4d14a13f3a
parent13f296db85e43116f5e1de944b6997dd98093640 (diff)
downloadarchive-2d7bd0389f1494040efcddd5a1b651f362bbf2c9.tar.gz
patch3....v0.96a-pl3
Ok, I already announced it on the kernel mailing-list, but I might as well go all the way. I put out patch3 to 0.96a yesterday, and it's available on banjo in pub/Linux/Linus, and I'll upload it to the other normal ftp-sites tonight. NOTE! Patch3 is (like patch2) more of a kernel-hacker patch: it's just in case you want to keep up with my kernel. It has some problems with some serial lines, and if you experience them, I'd like to know what type of chip you are running (and what linux reports on bootup). If you don't think patching the kernel is fun, you might as well forget this and wait for a real release (next month?). Patch 3 contains: - support for attaching and detaching processes under gdb (but you need a gdb that knows about this). - 16550A support - full core-dumping (again, you need a gdb that supports it) - sockets have no problems with non-root binding etc - /dev/zero implemented (mknod /dev/zero c 1 5) None of the patches are very big (the whole patch is 17kB compressed, most of it attach/detach code), but they are all pretty useful. The 16550A support means that with the appropriate chip you now should be able to use the serial ports at much higher speeds, but as mentioned, it seems to break on some machines. The detaching isn't perfect yet (I noticed only after making the diffs that I had forgotten to do some cleanups), but it's not generally a problem (the code just forgets to give the process back to it's rightful father). The patch is relative to the pl2 kernel, so you have to use the earlier patches first. This time, I've added the lib/itimer.c code. 16550A support was written by tdavis, the correct format of the core-dumps was written by eric (who also wrote the attach/detach code I used as an example when implementing it), /dev/zero was written by almesber. Nice to see good patches: I just did the socket-thing and rewrote the attaching to suit me. Linus
-rw-r--r--fs/exec.c61
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/namei.c11
-rw-r--r--fs/pipe.c6
-rw-r--r--include/linux/fs.h3
-rw-r--r--include/linux/sched.h20
-rw-r--r--include/sys/ptrace.h15
-rw-r--r--include/sys/user.h69
-rw-r--r--kernel/chr_drv/mem.c15
-rw-r--r--kernel/chr_drv/serial.c92
-rw-r--r--kernel/exit.c46
-rw-r--r--kernel/fork.c15
-rw-r--r--kernel/itimer.c8
-rw-r--r--kernel/ptrace.c94
-rw-r--r--kernel/signal.c7
-rw-r--r--lib/itimer.c12
-rw-r--r--net/unix.c13
17 files changed, 374 insertions, 115 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 48cc8ed..e8a58cb 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/segment.h>
+#include <sys/user.h>
extern int sys_exit(int exit_code);
extern int sys_close(int fd);
@@ -69,10 +70,14 @@ int core_dump(long signr, struct pt_regs * regs)
struct file file;
unsigned short fs;
int has_dumped = 0;
+ register int dump_start, dump_size;
+ struct user dump;
if (!current->dumpable)
return 0;
current->dumpable = 0;
+/* See if we have enough room to write the upage. */
+ if(current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE/1024) return 0;
__asm__("mov %%fs,%0":"=r" (fs));
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
if (open_namei("core",O_CREAT | O_WRONLY | O_TRUNC,0600,&inode))
@@ -96,22 +101,52 @@ int core_dump(long signr, struct pt_regs * regs)
has_dumped = 1;
/* write and seek example: from kernel space */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
- DUMP_WRITE("core-dump, regs=\n",17);
- DUMP_SEEK(64);
- DUMP_WRITE(regs,sizeof(*regs));
- if (current->used_math) {
+ dump.u_tsize = current->end_code / PAGE_SIZE;
+ dump.u_dsize = (current->brk - current->end_code) / PAGE_SIZE;
+ dump.u_ssize =((current->start_stack +(PAGE_SIZE-1)) / PAGE_SIZE) -
+ (regs->esp/ PAGE_SIZE);
+/* If the size of the dump file exceeds the rlimit, then see what would happen
+ if we wrote the stack, but not the data area. */
+ if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE/1024 >
+ current->rlim[RLIMIT_CORE].rlim_cur)
+ dump.u_dsize = 0;
+/* Make sure we have enough room to write the stack and data areas. */
+ if ((dump.u_ssize+1) * PAGE_SIZE / 1024 >
+ current->rlim[RLIMIT_CORE].rlim_cur)
+ dump.u_ssize = 0;
+ dump.u_comm = 0;
+ dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
+ dump.signal = signr;
+ dump.regs = *regs;
+ dump.start_code = 0;
+ dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
+/* Flag indicating the math stuff is valid. */
+ if (dump.u_fpvalid = current->used_math) {
if (last_task_used_math == current)
- __asm__("clts ; fnsave %0"::"m" (current->tss.i387));
- DUMP_SEEK(1024);
- DUMP_WRITE("floating-point regs=\n",21);
- DUMP_SEEK(1088);
- DUMP_WRITE(&current->tss.i387,sizeof(current->tss.i387));
- }
+ __asm__("clts ; fnsave %0"::"m" (dump.i387));
+ else
+ memcpy(&dump.i387,&current->tss.i387,sizeof(dump.i387));
+ };
+ DUMP_WRITE(&dump,sizeof(dump));
+ DUMP_SEEK(sizeof(dump));
+ /* Dump the task struct. Not be used by gdb, but could be useful */
+ DUMP_WRITE(current,sizeof(*current));
+/* Now dump all of the user data. Include malloced stuff as well */
+ DUMP_SEEK(PAGE_SIZE);
/* now we start writing out the user space info */
__asm__("mov %0,%%fs"::"r" ((unsigned short) 0x17));
-/* the dummy dump-file contains the first block of user space... */
- DUMP_SEEK(2048);
- DUMP_WRITE(0,1024);
+/* Dump the data area */
+ if (dump.u_dsize != 0) {
+ dump_start = current->end_code;
+ dump_size = current->brk - current->end_code;
+ DUMP_WRITE(dump_start,dump_size);
+ };
+/* Now prepare to dump the stack area */
+ if (dump.u_ssize != 0) {
+ dump_start = regs->esp & ~(PAGE_SIZE - 1);
+ dump_size = dump.u_ssize * PAGE_SIZE;
+ DUMP_WRITE(dump_start,dump_size);
+ };
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index df68ec5..f528743 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -58,8 +58,6 @@ struct super_block *minix_read_super(struct super_block *s,void *data)
printk("bread failed\n");
return NULL;
}
-/* *((struct minix_super_block *) s) =
- *((struct minix_super_block *) bh->b_data); */
ms = (struct minix_super_block *) bh->b_data;
s->s_ninodes = ms->s_ninodes;
s->s_nzones = ms->s_nzones;
diff --git a/fs/namei.c b/fs/namei.c
index 0a59da8..eccb04c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -252,14 +252,12 @@ int open_namei(const char * pathname, int flag, int mode,
return 0;
}
-int sys_mknod(const char * filename, int mode, int dev)
+int do_mknod(const char * filename, int mode, int dev)
{
const char * basename;
int namelen;
struct inode * dir;
- if (!suser())
- return -EPERM;
if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
return -ENOENT;
if (!namelen) {
@@ -277,6 +275,13 @@ int sys_mknod(const char * filename, int mode, int dev)
return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
+int sys_mknod(const char * filename, int mode, int dev)
+{
+ if (suser())
+ return do_mknod(filename,mode,dev);
+ return -EPERM;
+}
+
int sys_mkdir(const char * pathname, int mode)
{
const char * basename;
diff --git a/fs/pipe.c b/fs/pipe.c
index fa91c01..a3f48cd 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -49,11 +49,15 @@ static int pipe_write(struct inode * inode, struct file * filp, char * buf, int
{
int chars, size, written = 0;
+ if (inode->i_count != 2) { /* no readers */
+ send_sig(SIGPIPE,current,0);
+ return -EINTR;
+ }
while (count>0) {
while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
wake_up(& PIPE_READ_WAIT(*inode));
if (inode->i_count != 2) { /* no readers */
- current->signal |= (1<<(SIGPIPE-1));
+ send_sig(SIGPIPE,current,0);
return written?written:-EINTR;
}
if (current->signal & ~current->blocked)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 304b374..329f8ac 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -41,7 +41,7 @@ void buffer_init(long buffer_end);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
-#define NR_OPEN 20
+#define NR_OPEN 32
#define NR_INODE 128
#define NR_FILE 64
#define NR_SUPER 8
@@ -226,6 +226,7 @@ extern struct inode * _namei(const char * filename, struct inode * base,
int follow_links);
extern int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode);
+extern int do_mknod(const char * filename, int mode, int dev);
extern void iput(struct inode * inode);
extern struct inode * iget(int dev,int nr);
extern struct inode * get_empty_inode(void);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e301b34..249f8c0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -124,11 +124,11 @@ struct task_struct {
long pid,pgrp,session,leader;
int groups[NGROUPS];
/*
- * pointers to parent process, youngest child, younger sibling,
+ * pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
- struct task_struct *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+ struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr;
/*
* sleep makes a singly linked list with this.
*/
@@ -187,7 +187,7 @@ struct task_struct {
/* ec,brk... */ 0,0,0,0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
/* suppl grps*/ {NOGROUP,}, \
-/* proc links*/ &init_task.task,NULL,NULL,NULL,NULL, \
+/* proc links*/ &init_task.task,&init_task.task,NULL,NULL,NULL,NULL, \
/* uid etc */ 0,0,0,0,0,0, \
/* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \
/* min_flt */ 0,0,0,0, \
@@ -320,4 +320,18 @@ static unsigned long inline get_limit(unsigned long segment)
return __limit+1;
}
+#define REMOVE_LINKS(p) \
+ if ((p)->p_osptr) \
+ (p)->p_osptr->p_ysptr = (p)->p_ysptr; \
+ if ((p)->p_ysptr) \
+ (p)->p_ysptr->p_osptr = (p)->p_osptr; \
+ else \
+ (p)->p_pptr->p_cptr = (p)->p_osptr
+
+#define SET_LINKS(p) \
+ (p)->p_ysptr = NULL; \
+ if ((p)->p_osptr = (p)->p_pptr->p_cptr) \
+ (p)->p_osptr->p_ysptr = p; \
+ (p)->p_pptr->p_cptr = p
+
#endif
diff --git a/include/sys/ptrace.h b/include/sys/ptrace.h
index 14bf3c7..9d9defb 100644
--- a/include/sys/ptrace.h
+++ b/include/sys/ptrace.h
@@ -4,6 +4,21 @@
#ifndef _SYS_PTRACE_H
#define _SYS_PTRACE_H
/* has the defines to get at the registers. */
+
+#define PTRACE_TRACEME 0
+#define PTRACE_PEEKTEXT 1
+#define PTRACE_PEEKDATA 2
+#define PTRACE_PEEKUSR 3
+#define PTRACE_POKETEXT 4
+#define PTRACE_POKEDATA 5
+#define PTRACE_POKEUSR 6
+#define PTRACE_CONT 7
+#define PTRACE_KILL 8
+#define PTRACE_SINGLESTEP 9
+
+#define PTRACE_ATTACH 0x10
+#define PTRACE_DETACH 0x11
+
/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
the processes registers. */
diff --git a/include/sys/user.h b/include/sys/user.h
new file mode 100644
index 0000000..1531c9e
--- /dev/null
+++ b/include/sys/user.h
@@ -0,0 +1,69 @@
+#include <sys/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+ can understand it and provide useful information to the user (under
+ linux we use the 'trad-core' bfd). There are quite a number of
+ obstacles to being able to view the contents of the floating point
+ registers, and until these are solved you will not be able to view the
+ contents of them. Actually, you can read in the core file and look at
+ the contents of the user struct to find out what the floating point
+ registers contain.
+ The actual file contents are as follows:
+ UPAGE: 1 page consisting of a user struct that tells gdb what is present
+ in the file. Directly after this is a copy of the task_struct, which
+ is currently not used by gdb, but it may come in useful at some point.
+ All of the registers are stored as part of the upage. The upage should
+ always be only one page.
+ DATA: The data area is stored. We use current->end_text to
+ current->brk to pick up all of the user variables, plus any memory
+ that may have been malloced. No attempt is made to determine if a page
+ is demand-zero or if a page is totally unused, we just cover the entire
+ range. All of the addresses are rounded in such a way that an integral
+ number of pages is written.
+ STACK: We need the stack information in order to get a meaningful
+ backtrace. We need to write the data from (esp) to
+ current->start_stack, so we round each of these off in order to be able
+ to write an integer number of pages.
+ The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+struct user_i387_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+ this will be used by gdb to figure out where the data and stack segments
+ are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+ from the ptrace(3,...) function. */
+ struct pt_regs regs; /* Where the registers are actually stored */
+/* ptrace does not yet supply these. Someday.... */
+ int u_fpvalid; /* True if math co-processor being used. */
+ /* for this mess. Not yet used. */
+ struct user_i387_struct i387; /* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+ unsigned long int u_tsize; /* Text segment size (pages). */
+ unsigned long int u_dsize; /* Data segment size (pages). */
+ unsigned long int u_ssize; /* Stack segment size (pages). */
+ unsigned long start_code; /* Starting virtual address of text. */
+ unsigned long start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ long int signal; /* Signal that caused the core dump. */
+ char * u_comm; /* User command that was responsible */
+ struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
+ /* the registers. */
+ struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
+};
+#define NBPG 4096
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
diff --git a/kernel/chr_drv/mem.c b/kernel/chr_drv/mem.c
index 73758ee..db53a8e 100644
--- a/kernel/chr_drv/mem.c
+++ b/kernel/chr_drv/mem.c
@@ -154,6 +154,17 @@ static int write_port(struct inode * inode,struct file * file,char * buf, int co
return tmp-buf;
}
+static int read_zero(struct inode *node,struct file *file,char *buf,int count)
+{
+ int left;
+
+ for (left = count; left > 0; left--) {
+ put_fs_byte(0,buf);
+ buf++;
+ }
+ return count;
+}
+
/*
* The memory devices use the full 32 bits of the offset, and so we cannot
* check against negative addresses: they are ok. The return value is weird,
@@ -192,6 +203,8 @@ static int mem_read(struct inode * inode, struct file * file, char * buf, int co
return 0; /* /dev/null */
case 4:
return read_port(inode,file,buf,count);
+ case 5:
+ return read_zero(inode,file,buf,count);
default:
return -ENODEV;
}
@@ -210,6 +223,8 @@ static int mem_write(struct inode * inode, struct file * file, char * buf, int c
return count; /* /dev/null */
case 4:
return write_port(inode,file,buf,count);
+ case 5:
+ return count; /* /dev/zero */
default:
return -ENODEV;
}
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index 60e704b..f0bb652 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -27,12 +27,32 @@
extern void IRQ3_interrupt(void);
extern void IRQ4_interrupt(void);
+#define PORT_UNKNOWN 0
+#define PORT_8250 1
+#define PORT_16450 2
+#define PORT_16550 3
+#define PORT_16550A 4
+
+int port_table[] = {
+ PORT_UNKNOWN,
+ PORT_UNKNOWN,
+ PORT_UNKNOWN,
+ PORT_UNKNOWN,
+ PORT_UNKNOWN
+};
+
+
static void modem_status_intr(unsigned line, unsigned port, struct tty_struct * tty)
{
unsigned char status = inb(port+6);
if ((status & 0x88) == 0x08 && tty->pgrp > 0)
kill_pg(tty->pgrp,SIGHUP,1);
+
+ if ((status & 0x10) == 0x10)
+ tty->stopped = 0;
+ else
+ tty->stopped = 1;
}
/*
@@ -46,13 +66,20 @@ static void modem_status_intr(unsigned line, unsigned port, struct tty_struct *
*/
static void send_intr(unsigned line, unsigned port, struct tty_struct * tty)
{
- int c;
+ int c, i = 0;
#define TIMER ((SER1_TIMEOUT-1)+line)
timer_active &= ~(1 << TIMER);
- if ((c = GETCH(tty->write_q)) < 0)
- return;
- outb(c,port);
+ if (!tty->stopped) {
+ do {
+ if ((c = GETCH(tty->write_q)) < 0)
+ return;
+ outb(c,port);
+ i++;
+ } while ( port_table[line] == PORT_16550A && \
+ i < 14 && !EMPTY(tty->write_q) && \
+ !tty->stopped);
+ }
timer_table[TIMER].expires = jiffies + 10;
timer_active |= 1 << TIMER;
if (LEFT(tty->write_q) > WAKEUP_CHARS)
@@ -64,7 +91,15 @@ static void receive_intr(unsigned line, unsigned port, struct tty_struct * tty)
{
if (FULL(tty->read_q))
return;
- PUTCH(inb(port),tty->read_q);
+
+ outb_p((inb(port+4) & 0x0d), port+4);
+
+ do {
+ PUTCH(inb(port),tty->read_q);
+ } while ((inb(port+5) & 0x01 != 0) && !FULL(tty->read_q));
+
+ outb_p((inb(port+4) | 0x02), port+4);
+
timer_active |= (1<<(SER1_TIMER-1))<<line;
}
@@ -90,7 +125,7 @@ static void check_tty(unsigned line,struct tty_struct * tty)
if (!(port = tty->read_q->data))
return;
while (1) {
- ident = inb(port+2);
+ ident = inb(port+2) & 7;
if (ident & 1)
return;
ident >>= 1;
@@ -182,8 +217,43 @@ static void com4_timeout(void)
do_rs_write(4,tty_table+67);
}
-static void init(int port)
+static void init(int port, int line)
{
+ unsigned char status1, status2, scratch;
+
+ if (inb(port+5) == 0xff) {
+ port_table[line] = PORT_UNKNOWN;
+ return;
+ }
+
+ scratch = inb(port+7);
+ outb_p(0xa5, port+7);
+ status1 = inb(port+7);
+ outb_p(0x5a, port+7);
+ status2 = inb(port+7);
+ if (status1 == 0xa5 && status2 == 0x5a) {
+ outb_p(scratch, port+7);
+ outb_p(0x01, port+2);
+ scratch = inb(port+2) >> 6;
+ switch (scratch) {
+ case 0: printk("serial port at 0x%04x is a 16450\n", port);
+ port_table[line] = PORT_16450;
+ break;
+ case 1: printk("serial port at 0x%04x is unknown\n", port);
+ port_table[line] = PORT_UNKNOWN;
+ break;
+ case 2: printk("serial port at 0x%04x is a 16550 (FIFO's disabled)\n", port);
+ port_table[line] = PORT_16550;
+ outb_p(0x00, port+2);
+ break;
+ case 3: printk("serial port at 0x%04x is a 16550a (FIFO's enabled)\n", port);
+ port_table[line] = PORT_16550A;
+ outb_p(0xc7, port+2);
+ break;
+ }
+ } else
+ printk("serial port at 0x%04x is a 8250\n", port);
+
outb_p(0x80,port+3); /* set DLAB of line control reg */
outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
outb_p(0x00,port+1); /* MS of divisor */
@@ -243,10 +313,10 @@ void rs_init(void)
timer_table[SER4_TIMEOUT].expires = 0;
set_intr_gate(0x23,IRQ3_interrupt);
set_intr_gate(0x24,IRQ4_interrupt);
- init(tty_table[64].read_q->data);
- init(tty_table[65].read_q->data);
- init(tty_table[66].read_q->data);
- init(tty_table[67].read_q->data);
+ init(tty_table[64].read_q->data, 1);
+ init(tty_table[65].read_q->data, 2);
+ init(tty_table[66].read_q->data, 3);
+ init(tty_table[67].read_q->data, 4);
outb(inb_p(0x21)&0xE7,0x21);
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 1e6ec04..11f126a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -22,7 +22,7 @@ int send_sig(long sig,struct task_struct * p,int priv)
if (!p || (sig < 0) || (sig > 32))
return -EINVAL;
if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
- (current->euid != p->euid) && !suser())
+ (current->euid != p->euid) && (current->uid != p->uid) && !suser())
return -EPERM;
if (!sig)
return 0;
@@ -42,7 +42,7 @@ int send_sig(long sig,struct task_struct * p,int priv)
/* save the signal number for wait. */
p->exit_code = sig;
- /* we have to make sure the parent is awake. */
+ /* we have to make sure the parent process is awake. */
if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
p->p_pptr->state = TASK_RUNNING;
@@ -66,13 +66,7 @@ void release(struct task_struct * p)
for (i=1 ; i<NR_TASKS ; i++)
if (task[i] == p) {
task[i] = NULL;
- /* Update links */
- if (p->p_osptr)
- p->p_osptr->p_ysptr = p->p_ysptr;
- if (p->p_ysptr)
- p->p_ysptr->p_osptr = p->p_osptr;
- else
- p->p_pptr->p_cptr = p->p_osptr;
+ REMOVE_LINKS(p);
free_page((long) p);
return;
}
@@ -284,6 +278,15 @@ static int has_stopped_jobs(int pgrp)
return(0);
}
+static void forget_original_parent(struct task_struct * father)
+{
+ struct task_struct ** p;
+
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+ if (*p && (*p)->p_opptr == father)
+ (*p)->p_opptr = task[1];
+}
+
volatile void do_exit(long code)
{
struct task_struct *p;
@@ -294,6 +297,7 @@ volatile void do_exit(long code)
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
+ forget_original_parent(current);
iput(current->pwd);
current->pwd = NULL;
iput(current->root);
@@ -332,18 +336,18 @@ volatile void do_exit(long code)
* A. Make init inherit all the child processes
* B. Check to see if any process groups have become orphaned
* as a result of our exiting, and if they have any stopped
- * jons, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
+ * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
*/
while (p = current->p_cptr) {
current->p_cptr = p->p_osptr;
p->p_ysptr = NULL;
- p->flags &= ~PF_PTRACED;
+ p->flags &= ~PF_PTRACED;
p->p_pptr = task[1];
- p->p_osptr = task[1]->p_cptr;
- task[1]->p_cptr->p_ysptr = p;
- task[1]->p_cptr = p;
+ p->p_osptr = p->p_pptr->p_cptr;
+ p->p_osptr->p_ysptr = p;
+ p->p_pptr->p_cptr = p;
if (p->state == TASK_ZOMBIE)
- task[1]->signal |= (1<<(SIGCHLD-1));
+ p->p_pptr->signal |= (1<<(SIGCHLD-1));
/*
* process group orphan check
* Case ii: Our child is in a different pgrp
@@ -396,7 +400,7 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
verify_area(stat_addr,4);
repeat:
flag=0;
- for (p = current->p_cptr ; p ; p = p->p_osptr) {
+ for (p = current->p_cptr ; p ; p = p->p_osptr) {
if (pid>0) {
if (p->pid != pid)
continue;
@@ -426,7 +430,13 @@ repeat:
flag = p->pid;
if (stat_addr)
put_fs_long(p->exit_code, stat_addr);
- release(p);
+ if (p->p_opptr != p->p_pptr) {
+ REMOVE_LINKS(p);
+ p->p_pptr = p->p_opptr;
+ SET_LINKS(p);
+ send_sig(SIGCHLD,p->p_pptr,1);
+ } else
+ release(p);
#ifdef DEBUG_PROC_TREE
audit_ptree();
#endif
@@ -451,5 +461,3 @@ repeat:
}
return -ECHILD;
}
-
-
diff --git a/kernel/fork.c b/kernel/fork.c
index 784cbad..96464bc 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -107,13 +107,11 @@ int sys_fork(long ebx,long ecx,long edx,
task[nr] = p;
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
p->state = TASK_UNINTERRUPTIBLE;
+ p->flags &= ~PF_PTRACED;
p->pid = last_pid;
- p->p_pptr = current;
+ p->p_pptr = p->p_opptr = current;
p->p_cptr = NULL;
- p->p_ysptr = NULL;
- if (p->p_osptr = current->p_cptr)
- p->p_osptr->p_ysptr = p;
- current->p_cptr = p;
+ SET_LINKS(p);
p->counter = p->priority;
p->signal = 0;
p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
@@ -151,12 +149,7 @@ int sys_fork(long ebx,long ecx,long edx,
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
if (copy_mem(nr,p)) {
task[nr] = NULL;
- if (p->p_pptr->p_cptr == p)
- p->p_pptr->p_cptr = p->p_osptr;
- if (p->p_osptr)
- p->p_osptr->p_ysptr = p->p_ysptr;
- if (p->p_ysptr)
- p->p_ysptr->p_osptr = p->p_osptr;
+ REMOVE_LINKS(p);
free_page((long) p);
return -EAGAIN;
}
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 7362dc8..f7e5ba3 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -16,7 +16,8 @@
static unsigned long tvtojiffies(struct timeval *value)
{
return((unsigned long )value->tv_sec * HZ +
- (unsigned long )value->tv_usec / (1000000 / HZ));
+ (unsigned long )(value->tv_usec + (1000000 / HZ - 1)) /
+ (1000000 / HZ));
}
static void jiffiestotv(unsigned long jiffies, struct timeval *value)
@@ -100,8 +101,9 @@ int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
int k;
if (!value)
- return -EFAULT;
- memcpy_fromfs(&set_buffer, value, sizeof(set_buffer));
+ memset((char *) &set_buffer, 0, sizeof(set_buffer));
+ else
+ memcpy_fromfs(&set_buffer, value, sizeof(set_buffer));
k = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
if (k < 0 || !ovalue)
return k;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 60e3d6d..7b6905d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -6,9 +6,11 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <errno.h>
+
#include <asm/segment.h>
#include <asm/system.h>
+
+#include <errno.h>
#include <sys/ptrace.h>
/*
@@ -33,15 +35,15 @@ void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned lon
void write_verify(unsigned long);
/* change a pid into a task struct. */
-static inline int get_task(int pid)
+static inline struct task_struct * get_task(int pid)
{
int i;
for (i = 0; i < NR_TASKS; i++) {
if (task[i] != NULL && (task[i]->pid == pid))
- return i;
+ return task[i];
}
- return -1;
+ return NULL;
}
/*
@@ -222,32 +224,50 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
- int childno;
- if (request == 0) {
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->flags & PF_PTRACED)
+ return -EPERM;
/* set the ptrace bit in the proccess flags. */
current->flags |= PF_PTRACED;
return 0;
}
-
- childno = get_task(pid);
-
- if (childno < 0)
+ if (!(child = get_task(pid)))
return -ESRCH;
- else
- child = task[childno];
-
- if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
- child->state != TASK_STOPPED)
+ if (request == PTRACE_ATTACH) {
+ long tmp;
+
+ if ((!current->dumpable || (current->uid != child->euid) ||
+ (current->gid != child->egid)) && !suser())
+ return -EPERM;
+ /* the same process cannot be attached many times */
+ if (child->flags & PF_PTRACED)
+ return -EPERM;
+ child->flags |= PF_PTRACED;
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ if (child->state == TASK_INTERRUPTIBLE ||
+ child->state == TASK_STOPPED)
+ child->state = TASK_RUNNING;
+ child->signal = 0;
+ return 0;
+ }
+ if (!(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
return -ESRCH;
switch (request) {
/* when I and D space are seperate, these will need to be fixed. */
- case 1: /* read word at location addr. */
- case 2: {
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
int tmp,res;
- res = read_long(task[childno], addr, &tmp);
+ res = read_long(child, addr, &tmp);
if (res < 0)
return res;
verify_area((void *) data, 4);
@@ -256,7 +276,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
}
/* read the word at location addr in the USER area. */
- case 3: {
+ case PTRACE_PEEKUSR: {
int tmp;
addr = addr >> 2; /* temporary hack. */
if (addr < 0 || addr >= 17)
@@ -268,11 +288,11 @@ int sys_ptrace(long request, long pid, long addr, long data)
}
/* when I and D space are seperate, this will have to be fixed. */
- case 4: /* write the word at location addr. */
- case 5:
- return write_long(task[childno],addr,data);
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ return write_long(child,addr,data);
- case 6: /* write the word at location addr in the USER area */
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
addr = addr >> 2; /* temproary hack. */
if (addr < 0 || addr >= 17)
return -EIO;
@@ -286,13 +306,13 @@ int sys_ptrace(long request, long pid, long addr, long data)
return -EIO;
return 0;
- case 7: { /* restart after signal. */
+ case PTRACE_CONT: { /* restart after signal. */
long tmp;
- child->signal=0;
+ child->signal = 0;
if (data > 0 && data <= NSIG)
child->signal = 1<<(data-1);
- child->state = 0;
+ child->state = TASK_RUNNING;
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
@@ -304,10 +324,10 @@ int sys_ptrace(long request, long pid, long addr, long data)
* perhaps it should be put in the status that it want's to
* exit.
*/
- case 8: {
+ case PTRACE_KILL: {
long tmp;
- child->state = 0;
+ child->state = TASK_RUNNING;
child->signal = 1 << (SIGKILL-1);
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
@@ -315,19 +335,31 @@ int sys_ptrace(long request, long pid, long addr, long data)
return 0;
}
- case 9: { /* set the trap flag. */
+ case PTRACE_SINGLESTEP: { /* set the trap flag. */
long tmp;
tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
- child->state = 0;
+ child->state = TASK_RUNNING;
child->signal = 0;
- if (data > 0 && data <NSIG)
+ if (data > 0 && data <= NSIG)
child->signal= 1<<(data-1);
/* give it a chance to run. */
return 0;
}
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ long tmp;
+
+ child->flags &= ~PF_PTRACED;
+ child->signal=0;
+ child->state = 0;
+ /* make sure the single step bit is not set. */
+ tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
+ put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
+ return 0;
+ }
+
default:
return -EIO;
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 77dd96d..03798a8 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -137,8 +137,7 @@ int do_signal(long signr,struct pt_regs * regs)
#endif
if ((regs->orig_eax != -1) &&
((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
- if ((regs->eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) ||
- signr < SIGCONT || signr > SIGTTOU))
+ if ((regs->eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT)))
regs->eax = -EINTR;
else {
regs->eax = regs->orig_eax;
@@ -168,9 +167,7 @@ int do_signal(long signr,struct pt_regs * regs)
current->exit_code = signr;
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- send_sig(SIGCHLD, current->p_pptr, 1);
-/* current->p_pptr->signal |= (1<<(SIGCHLD-1));*/
-
+ send_sig(SIGCHLD, current->p_pptr, 1);
return(1); /* Reschedule another event */
case SIGQUIT:
diff --git a/lib/itimer.c b/lib/itimer.c
new file mode 100644
index 0000000..9692eeb
--- /dev/null
+++ b/lib/itimer.c
@@ -0,0 +1,12 @@
+/*
+ * linux/lib/itimer.c
+ *
+ * (C) 1992 Darren Senn
+ */
+
+#define __LIBRARY__
+#include <unistd.h>
+#include <sys/time.h>
+
+_syscall2(int,getitimer,int,which,struct itimerval *,value)
+_syscall3(int,setitimer,int,which,struct itimerval *,value,struct itimerval *,ovalue)
diff --git a/net/unix.c b/net/unix.c
index 5a03b91..441d709 100644
--- a/net/unix.c
+++ b/net/unix.c
@@ -233,7 +233,6 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
int i;
unsigned long old_fs;
- unsigned short old_euid;
PRINTK("unix_proto_bind: socket 0x%x, len=%d\n", sock,
sockaddr_len);
@@ -254,21 +253,11 @@ unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
return -EINVAL;
}
- /*
- * W A R N I N G
- * this is a terrible hack. i want to create a socket in the
- * filesystem and get its inode. sys_mknod() can create one for
- * me, but it needs superuser privs and doesn't give me the inode.
- * we fake suser here and get the file created... ugh.
- */
memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
old_fs = get_fs();
set_fs(get_ds());
- old_euid = current->euid;
- current->euid = 0;
- i = sys_mknod(fname, S_IFSOCK, 0);
- current->euid = old_euid;
+ i = do_mknod(fname, S_IFSOCK | 0777, 0);
if (i == 0)
i = open_namei(fname, 0, S_IFSOCK, &upd->inode);
set_fs(old_fs);