aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1992-12-21 23:36:46 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:11 -0400
commitd99dedeec6209a2772ff0525eea13509181b9a2c (patch)
treee2ffc8c2f9d26ed297ea5e695fb2ffc35123ef24
parentca87352f20470de289c53a58c877df452e8b982c (diff)
downloadarchive-d99dedeec6209a2772ff0525eea13509181b9a2c.tar.gz
ANNOUNCE: linux 0.99 patchlevel 1v0.99-pl1
Linux-0.99.1 is now available on nic.funet.fi, and will probably show up on the other linux ftp sites within days, unless everybody has gone off for the holidays. The directory is /pub/OS/Linux/PEOPLE/Linus, and it's available both as a patch against 0.99 and as complete source. The patch is pretty clean, although most people probably have changed 0.99 slightly to get rid of the setup and/or inode.c problems, so if you have, you'll have to revert or patch by hand. Patch 1 addresses the following problems: - configuration. Hope there are no silly problems left.. - inode.c: initialization changes (the missing NULL and some other minor fixes). - some SCSI tape driver patches (Kai M{kisara) - tcp/ip patches (Ross Biro, some code by me) - keyboard patches (mainly changed initialization - hope the keyboard lockups are gone). - completed /proc-fs: it should now contain all info needed by 'ps' (Micheal K Johnson). - various minor fixes (the minix-fs link overflow checking etc) Patch1 also contains support for extended VC switching - this is for the upcoming X11 that understands VC's. One result of this is that console redirection now redirects *only* messages actually sent to /dev/console (aka /dev/tty0), not just to any foreground VC. Wait for Xfree-1.2 to be able to switch VC's while under X (yes, including several X-sessions active at the same time..). I hope there are still people out there that aren't too busy stuffing themself with turkey to try out a new kernel release. There is just over a week left of this year, and I need feedback in order to be able to release 1.0. Linus PS. Thanks to everybody who has sent me Christmas/New Year/Birthday cards. Some contained money, some didn't, and I enjoyed them all. Thanks.
-rw-r--r--Makefile35
-rw-r--r--boot/bootsect.S4
-rw-r--r--config.in8
-rw-r--r--fs/exec.c15
-rw-r--r--fs/inode.c16
-rw-r--r--fs/isofs/inode.c4
-rw-r--r--fs/minix/namei.c7
-rw-r--r--fs/proc/array.c110
-rw-r--r--fs/proc/base.c3
-rw-r--r--fs/proc/inode.c1
-rw-r--r--include/linux/autoconf.h2
-rw-r--r--include/linux/fs.h4
-rw-r--r--include/linux/keyboard.h35
-rw-r--r--include/linux/sys.h14
-rw-r--r--include/linux/tty.h1
-rw-r--r--init/main.c4
-rw-r--r--kernel/FPU-emu/fpu_entry.c2
-rw-r--r--kernel/blk_drv/blk.h3
-rw-r--r--kernel/blk_drv/scsi/scsi_ioctl.c2
-rw-r--r--kernel/blk_drv/scsi/sr_ioctl.c1
-rw-r--r--kernel/blk_drv/scsi/st.c49
-rw-r--r--kernel/blk_drv/scsi/st.h4
-rw-r--r--kernel/chr_drv/console.c26
-rw-r--r--kernel/chr_drv/keyboard.c114
-rw-r--r--kernel/chr_drv/psaux.c6
-rw-r--r--kernel/chr_drv/pty.c6
-rw-r--r--kernel/chr_drv/serial.c13
-rw-r--r--kernel/chr_drv/tty_io.c270
-rw-r--r--kernel/chr_drv/tty_ioctl.c12
-rw-r--r--kernel/chr_drv/vt.c186
-rw-r--r--kernel/chr_drv/vt_kern.h8
-rw-r--r--kernel/fork.c28
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/ptrace.c2
-rw-r--r--net/Makefile5
-rw-r--r--net/tcp/Makefile4
-rw-r--r--net/tcp/arp.c75
-rw-r--r--net/tcp/sock.c35
-rw-r--r--net/tcp/tcp.c320
-rw-r--r--net/tcp/tcp.h10
-rw-r--r--net/tcp/timer.c37
-rw-r--r--net/unix.c26
-rw-r--r--tools/version.h6
43 files changed, 1092 insertions, 423 deletions
diff --git a/Makefile b/Makefile
index 42d893c..d740d50 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,11 @@
+#
+# Make "config" the default target if there is no configuration file
+#
+ifeq (.config,$(wildcard .config))
include .config
+else
+CONFIGURATION = config
+endif
#
# ROOT_DEV specifies the default root-device when making the image.
@@ -69,6 +76,10 @@ SOUND_SUPPORT = -DKERNEL_SOUNDCARD -DDSP_BUFFSIZE=16384 -DSBC_IRQ=7 -DPAS_IRQ=5
CFLAGS = -Wall -O6 -fomit-frame-pointer
+ifdef CONFIG_M486
+CFLAGS := $(CFLAGS) -m486
+endif
+
#
# if you want the ram-disk device, define this to be the
# size in blocks.
@@ -112,20 +123,31 @@ lilo: Image
/etc/lilo/install
config:
+ifdef CONFIGURATION
+ @echo
+ @echo "You have no .config: running Configure"
+ @echo
+endif
sh Configure < config.in
+ifdef CONFIGURATION
+ @echo
+ @echo "Configure successful. Try re-making (ignore the error that follows)"
+ @echo
+ exit 1
+endif
linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
-Version:
+Version: dummy
@./makever.sh
- @echo \#define UTS_RELEASE \"0.99-`cat .version`\" > tools/version.h
+ @echo \#define UTS_RELEASE \"0.99.pl1-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
-Image: boot/bootsect boot/setup tools/system tools/build
+Image: $(CONFIGURATION) boot/bootsect boot/setup tools/system tools/build
cp tools/system system.tmp
strip system.tmp
tools/build boot/bootsect boot/setup system.tmp $(ROOT_DEV) > Image
@@ -162,8 +184,8 @@ boot/setup: boot/setup.s
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
-boot/setup.s: boot/setup.S include/linux/config.h
- $(CPP) -traditional boot/setup.S -o boot/setup.s
+boot/setup.s: boot/setup.S include/linux/config.h Makefile
+ $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/setup.S -o boot/setup.s
boot/bootsect.s: boot/bootsect.S include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) boot/bootsect.S -o boot/bootsect.s
@@ -195,7 +217,7 @@ depend dep:
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend
for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
-dummy:
+dummy: $(CONFIGURATION)
#
# include a dependency file if one exists
@@ -203,3 +225,4 @@ dummy:
ifeq (.depend,$(wildcard .depend))
include .depend
endif
+
diff --git a/boot/bootsect.S b/boot/bootsect.S
index d9a44b2..075c4be 100644
--- a/boot/bootsect.S
+++ b/boot/bootsect.S
@@ -78,8 +78,6 @@ go: mov ax,cs
mov ds,ax
mov es,ax
- push ax
-
mov ss,ax ! put stack at INITSEG:0x4000-12.
mov sp,dx
/*
@@ -121,7 +119,7 @@ go: mov ax,cs
seg fs
mov 2(bx),es
- pop ax
+ mov ax,cs
mov fs,ax
mov gs,ax
diff --git a/config.in b/config.in
index f81aca0..0514139 100644
--- a/config.in
+++ b/config.in
@@ -10,6 +10,8 @@ Kernel profiling support
CONFIG_PROFILE y/n n
Limit to memory to low 16MB
CONFIG_MAX_16M y/n y
+Use -m486 flag for 486-specific optimizations
+CONFIG_M486 y/n y
:
SCSI support
.
@@ -27,9 +29,9 @@ CONFIG_BLK_DEV_SR y/n y
.
SCSI low-level drivers
.
-Adaptek AHA1542 support
+Adaptec AHA1542 support
CONFIG_SCSI_AHA1542 y/n y
-Adaptek AHA1740 support
+Adaptec AHA1740 support
CONFIG_SCSI_AHA1740 y/n y
Always IN support
CONFIG_SCSI_ALWAYS y/n y
@@ -67,7 +69,7 @@ Accent Async 4 serial support
CONFIG_ACCENT_ASYNC y/n n
Logitech busmouse support
CONFIG_BUSMOUSE y/n n
-PS/2 mouse (aka 'auxilliary device') support
+PS/2 mouse (aka 'auxiliary device') support
CONFIG_PSMOUSE y/n n
MicroSoft busmouse support
CONFIG_MS_BUSMOUSE y/n n
diff --git a/fs/exec.c b/fs/exec.c
index 62ea594..2942228 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -376,17 +376,18 @@ static void read_omagic(struct inode *inode, int bytes)
if (inode->i_sb)
block_size = inode->i_sb->s_blocksize;
while (bytes > 0) {
- if (!(blkno = bmap(inode, blk)))
- sys_exit(-1);
- if (!(bh = bread(inode->i_dev, blkno, block_size)))
- sys_exit(-1);
n = (blk ? block_size : block_size - sizeof(struct exec));
if (bytes < n)
n = bytes;
-
- memcpy_tofs(dest, (blk ? bh->b_data :
+ blkno = bmap(inode, blk);
+ if (blkno) {
+ bh = bread(inode->i_dev, blkno, block_size);
+ if (!bh)
+ sys_exit(-1);
+ memcpy_tofs(dest, (blk ? bh->b_data :
bh->b_data + sizeof(struct exec)), n);
- brelse(bh);
+ brelse(bh);
+ }
++blk;
dest += n;
bytes -= n;
diff --git a/fs/inode.c b/fs/inode.c
index d1eb15e..92ed94f 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -12,13 +12,19 @@
#include <asm/system.h>
-static struct inode inode_table[NR_INODE];
-static struct inode * last_inode = inode_table;
-static struct wait_queue * inode_wait;
+static struct inode * inode_table;
+static struct inode * last_inode;
+static struct wait_queue * inode_wait = NULL;
-void inode_init(void)
+unsigned long inode_init(unsigned long start, unsigned long end)
{
- memset(inode_table,0,sizeof(inode_table));
+ start += 0x0000000f;
+ start &= 0xfffffff0;
+ inode_table = (struct inode *) start;
+ last_inode = inode_table;
+ start = (unsigned long) (inode_table + NR_INODE);
+ memset(inode_table,0,NR_INODE*sizeof(struct inode));
+ return start;
}
static void __wait_on_inode(struct inode *);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 57981c1..39b00fa 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -18,10 +18,6 @@
#include <asm/segment.h>
#include <linux/errno.h>
-#ifndef CONFIG_BLK_DEV_SR
-#error The iso9660 filesystem can only be used with CDROM.
-#endif
-
extern int check_cdrom_media_change(int, int);
#ifdef LEAK_CHECK
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 45242f7..ec6cb63 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -304,6 +304,10 @@ int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
iput(dir);
return -EEXIST;
}
+ if (dir->i_nlink > 250) {
+ iput(dir);
+ return -EMLINK;
+ }
inode = minix_new_inode(dir);
if (!inode) {
iput(dir);
@@ -695,6 +699,9 @@ start_up:
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
+ retval = -EMLINK;
+ if (new_dir->i_nlink > 250)
+ goto end_rename;
}
if (!new_bh)
new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 3d8db0b..f9e4b0e 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -3,12 +3,15 @@
*
* Copyright (C) 1992 by Linus Torvalds
* based on ideas by Darren Senn
+ *
+ * stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/tty.h>
#include <asm/segment.h>
#include <asm/io.h>
@@ -16,6 +19,17 @@
#define LOAD_INT(x) ((x) >> FSHIFT)
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+#define KSTK_EIP(stack) (((char *)stack)[1019])
+#define KSTK_ESP(stack) (((char *)stack)[1022])
+
+#define _SSIZE(stack) (TASK_SIZE - KSTK_ESP(stack))
+#define SSIZE(stack) (KSTK_ESP(stack) ? _SSIZE(stack) : 0)
+
+#define VSIZE(task,stack) ((task)->brk + 1023 + SSIZE(stack))
+#define SIZE(task,stack) (((task)->brk - (task)->end_code + 1023 + \
+ SSIZE(stack)) / 1024)
+
+
static int get_loadavg(char * buffer)
{
int a, b, c;
@@ -129,6 +143,8 @@ static int get_arg(int pid, char * buffer)
static int get_stat(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
+ unsigned long sigignore=0, sigcatch=0, bit=1;
+ int i;
char state;
if (!p || !*p)
@@ -137,14 +153,101 @@ static int get_stat(int pid, char * buffer)
state = '.';
else
state = "RSDZTD"[(*p)->state];
- return sprintf(buffer,"%d (%s) %c %d %d %d %d\n",
+ for(i=0; i<32; ++i) {
+ switch((int) (*p)->sigaction[i].sa_handler) {
+ case 1: sigignore |= bit; break;
+ case 0: break;
+ default: sigcatch |= bit;
+ } bit <<= 1;
+ }
+ return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %u \
+%u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d \
+%d %d %d %u\n",
pid,
(*p)->comm,
state,
(*p)->p_pptr->pid,
(*p)->pgrp,
(*p)->session,
- (*p)->tty);
+ (*p)->tty,
+ ((*p)->tty == -1) ? -1 :
+ tty_table[(*p)->tty]->pgrp,
+ (*p)->flags,
+ (*p)->min_flt,
+ (*p)->cmin_flt,
+ (*p)->maj_flt,
+ (*p)->cmaj_flt,
+ (*p)->utime,
+ (*p)->stime,
+ (*p)->cutime,
+ (*p)->cstime,
+ (*p)->counter, /* this is the kernel priority ---
+ subtract 30 in your user-level program. */
+ (*p)->priority, /* this is the nice value ---
+ subtract 15 in your user-level program. */
+ (*p)->timeout,
+ (*p)->it_real_value,
+ (*p)->start_time,
+ VSIZE((*p),(*p)->kernel_stack_page),
+ (*p)->rss, /* you might want to shift this left 3 */
+ (*p)->rlim[RLIMIT_RSS].rlim_cur,
+ (*p)->start_code,
+ (*p)->end_code,
+ (*p)->start_stack,
+ KSTK_ESP((*p)->kernel_stack_page),
+ KSTK_EIP((*p)->kernel_stack_page),
+ (*p)->signal,
+ (*p)->blocked,
+ sigignore,
+ sigcatch,
+ (*p)->tss.eip);
+}
+
+static int get_statm(int pid, char * buffer)
+{
+ struct task_struct ** p = get_task(pid);
+ int i, tpag;
+ int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
+ unsigned long ptbl, *buf, *pte, *pagedir, map_nr;
+
+ if (!p || !*p)
+ return 0;
+ tpag = (*p)->end_code / PAGE_SIZE;
+ if ((*p)->state != TASK_ZOMBIE) {
+ pagedir = (void *)((*p)->tss.cr3 + ((*p)->start_code >> 20));
+ for (i = 0; i < 0x300; ++i) {
+ if ((ptbl = pagedir[i]) == 0) {
+ tpag -= 1024;
+ continue;
+ }
+ buf = (void *)(ptbl & 0xfffff000);
+ for (pte = buf; pte < (buf + 1024); ++pte) {
+ if (*pte != 0) {
+ ++size;
+ if (*pte & 1) {
+ ++resident;
+ if (tpag > 0)
+ ++trs;
+ else
+ ++drs;
+ if (i >= 15 && i < 0x2f0) {
+ ++lrs;
+ if (*pte & 0x40)
+ ++dt;
+ else
+ --drs;
+ }
+ map_nr = MAP_NR(*pte);
+ if (map_nr < (high_memory / 4096) && mem_map[map_nr] > 1)
+ ++share;
+ }
+ }
+ --tpag;
+ }
+ }
+ }
+ return sprintf(buffer,"%d %d %d %d %d %d %d\n",
+ size, resident, share, trs, lrs, drs, dt);
}
static int array_read(struct inode * inode, struct file * file,char * buf, int count)
@@ -181,6 +284,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
case 11:
length = get_stat(pid, page);
break;
+ case 12:
+ length = get_statm(pid, page);
+ break;
default:
free_page((unsigned long) page);
return -EBADF;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index fc37cc4..24e8210 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -59,7 +59,8 @@ static struct proc_dir_entry base_dir[] = {
{ 8,3,"lib" },
{ 9,7,"environ" },
{ 10,7,"cmdline" },
- { 11,4,"stat" }
+ { 11,4,"stat" },
+ { 12,5,"statm" }
};
#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 9f206b0..07ceb81 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -143,6 +143,7 @@ void proc_read_inode(struct inode * inode)
case 9:
case 10:
case 11:
+ case 12:
inode->i_mode = S_IFREG | 0444;
inode->i_op = &proc_array_inode_operations;
return;
diff --git a/include/linux/autoconf.h b/include/linux/autoconf.h
index 172aac3..e6db1e5 100644
--- a/include/linux/autoconf.h
+++ b/include/linux/autoconf.h
@@ -7,8 +7,8 @@
*/
#define CONFIG_BLK_DEV_HD 1
#define CONFIG_TCPIP 1
-#define CONFIG_PROFILE 1
#define CONFIG_MAX_16M 1
+#define CONFIG_M486 1
/*
* SCSI support
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c00154d..1814376 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -23,7 +23,7 @@
#undef NR_OPEN
#define NR_OPEN 256
-#define NR_INODE 128
+#define NR_INODE 256
#define NR_FILE 128
#define NR_SUPER 16
#define NR_HASH 997
@@ -66,7 +66,7 @@
#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
extern void buffer_init(void);
-extern void inode_init(void);
+extern unsigned long inode_init(unsigned long start, unsigned long end);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index b3f01b6..dfae10f 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -23,8 +23,19 @@ extern unsigned long kbd_flags;
#define KG_ALT 4
#define KG_ALTGR 5
#define KG_CAPSLOCK 6
-#define KG_E0 7
-#define KG_E1 8
+
+/*
+ * "dead" keys - prefix key values that are valid only for the next
+ * character code (sticky shift, E0/E1 special scancodes, diacriticals)
+ */
+extern unsigned long kbd_dead_keys;
+extern unsigned long kbd_prev_dead_keys;
+
+/*
+ * these are the hardcoded dead key flags
+ */
+#define KGD_E0 0
+#define KGD_E1 1
/*
* kbd->xxx contains the VC-local things (flag settings etc..)
@@ -80,6 +91,26 @@ extern inline void chg_kbd_flag(int flag)
kbd_flags ^= 1 << flag;
}
+extern inline int kbd_dead(int flag)
+{
+ return kbd_prev_dead_keys & (1 << flag);
+}
+
+extern inline void set_kbd_dead(int flag)
+{
+ kbd_dead_keys |= 1 << flag;
+}
+
+extern inline void clr_kbd_dead(int flag)
+{
+ kbd_dead_keys &= ~(1 << flag);
+}
+
+extern inline void chg_kbd_dead(int flag)
+{
+ kbd_dead_keys ^= 1 << flag;
+}
+
extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag)
{
return ((kbd->flags >> flag) & 1);
diff --git a/include/linux/sys.h b/include/linux/sys.h
index c5c831c..45ae421 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -134,14 +134,14 @@ sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending,
sys_sethostname, sys_setrlimit, sys_getrlimit, sys_getrusage,
-sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups,
+sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups,
sys_select, sys_symlink, sys_lstat, sys_readlink, sys_uselib,
-sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap,
-sys_truncate, sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority,
-sys_setpriority, sys_profil, sys_statfs, sys_fstatfs, sys_ioperm,
-sys_socketcall, sys_syslog, sys_setitimer, sys_getitimer, sys_newstat,
-sys_newlstat, sys_newfstat, sys_newuname, sys_iopl, sys_vhangup,
-sys_idle, sys_vm86, sys_wait4, sys_swapoff, sys_sysinfo };
+sys_swapon, sys_reboot, sys_readdir, sys_mmap, sys_munmap, sys_truncate,
+sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
+sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall,
+sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
+sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
+sys_wait4, sys_swapoff, sys_sysinfo };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 0b26653..e529d7f 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -285,6 +285,7 @@ extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty);
extern int kill_pg(int pgrp, int sig, int priv);
extern int kill_sl(int sess, int sig, int priv);
+extern void tty_hangup(struct tty_struct * tty);
extern void do_SAK(struct tty_struct *tty);
/* tty write functions */
diff --git a/init/main.c b/init/main.c
index 89b351e..cb47e84 100644
--- a/init/main.c
+++ b/init/main.c
@@ -133,7 +133,7 @@ static unsigned long memory_start = 0; /* After mem_init, stores the */
static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0;
-static char * argv_init[MAX_INIT_ARGS+2] = { "/bin/init", NULL, };
+static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, };
static char * argv_rc[] = { "/bin/sh", NULL };
@@ -238,9 +238,9 @@ void start_kernel(void)
#ifdef CONFIG_SCSI
memory_start = scsi_dev_init(memory_start,memory_end);
#endif
+ memory_start = inode_init(memory_start,memory_end);
mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
- inode_init();
time_init();
floppy_init();
sock_init();
diff --git a/kernel/FPU-emu/fpu_entry.c b/kernel/FPU-emu/fpu_entry.c
index d1c8934..3dc9c64 100644
--- a/kernel/FPU-emu/fpu_entry.c
+++ b/kernel/FPU-emu/fpu_entry.c
@@ -288,6 +288,8 @@ void __math_abort(struct info * info, unsigned int signal)
void math_emulate(long arg)
{
+ printk("math-meulation not enabled and no coprocessor found.\n");
+ printk("killing %s.\n",current->comm);
send_sig(SIGFPE,current,1);
schedule();
}
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index 792cae9..dbd9718 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -152,6 +152,8 @@ extern int ramdisk_size;
#endif
+#if (MAJOR_NR != 9)
+
#ifndef CURRENT
#define CURRENT (blk_dev[MAJOR_NR].current_request)
#endif
@@ -259,3 +261,4 @@ static void end_request(int uptodate)
#endif
#endif
+#endif
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/kernel/blk_drv/scsi/scsi_ioctl.c
index 8516a03..b8a5661 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.c
+++ b/kernel/blk_drv/scsi/scsi_ioctl.c
@@ -216,7 +216,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{
char scsi_cmd[10];
- if ((cmd != 0 && dev->id > NR_SCSI_DEVICES))
+ if ((cmd != 0 && dev->index > NR_SCSI_DEVICES))
return -ENODEV;
if ((cmd == 0 && dev->host_no > max_scsi_hosts))
return -ENODEV;
diff --git a/kernel/blk_drv/scsi/sr_ioctl.c b/kernel/blk_drv/scsi/sr_ioctl.c
index bffa55e..af9b4dc 100644
--- a/kernel/blk_drv/scsi/sr_ioctl.c
+++ b/kernel/blk_drv/scsi/sr_ioctl.c
@@ -97,6 +97,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned long cmd, unsign
int result, target;
target = MINOR(dev);
+ if (target >= NR_SR) return -ENODEV;
switch (cmd)
{
diff --git a/kernel/blk_drv/scsi/st.c b/kernel/blk_drv/scsi/st.c
index 3ff1abb..9ede064 100644
--- a/kernel/blk_drv/scsi/st.c
+++ b/kernel/blk_drv/scsi/st.c
@@ -30,7 +30,7 @@
Kai Makisara, Nov 9, 1992 email makisara@vtinsx.ins.vtt.fi or
Kai.Makisara@vtt.fi
- Last changes Dec 6, 1992.
+ Last changes Dec 19, 1992.
*/
#include <linux/fs.h>
@@ -56,9 +56,14 @@
before command completion. */
/* #define ST_NOWAIT */
+/* Uncomment the following if you want the tape to be positioned correctly
+ within file after close (the tape is positioned correctly with respect
+ to the filemarks even wihout ST_IN_FILE_POS defined */
+/* #define ST_IN_FILE_POS */
+
/* #define DEBUG */
-#define ST_TIMEOUT 2000
+#define ST_TIMEOUT 6000
#define ST_LONG_TIMEOUT 200000
/* Number of ST_BLOCK_SIZE blocks in the buffers */
@@ -519,9 +524,13 @@ static void scsi_tape_close(struct inode * inode, struct file * filp)
printk("st%d: Buffer flushed, EOF written\n", dev);
#endif
}
- else if (!rewind && scsi_tapes[dev].eof && !scsi_tapes[dev].eof_hit)
- st_int_ioctl(inode, filp, MTBSF, 1);
- /* Back over the EOF hit inadvertently */
+ else if (!rewind) {
+ if ((scsi_tapes[dev].eof == 1) && !scsi_tapes[dev].eof_hit)
+ st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */
+#ifdef ST_IN_FILE_POS
+ flush_buffer(inode, filp, 0);
+#endif
+ }
if (rewind)
st_int_ioctl(inode, filp, MTREW, 1);
@@ -701,12 +710,9 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
printk("st%d: EOF flag up. Bytes %d\n", dev,
scsi_tapes[dev].buffer->buffer_bytes);
#endif
- if ((scsi_tapes[dev].buffer->buffer_bytes == 0) && scsi_tapes[dev].eof) {
- if (scsi_tapes[dev].eof == 1)
- return 0;
- else /* EOM or blank check */
- return (-EIO);
- }
+ if ((scsi_tapes[dev].buffer->buffer_bytes == 0) &&
+ scsi_tapes[dev].eof == 2) /* EOM or Blank Check */
+ return (-EIO);
scsi_tapes[dev].rw = 1;
@@ -714,7 +720,8 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
for (total = 0; total < count; ) {
- if (scsi_tapes[dev].buffer->buffer_bytes == 0 && scsi_tapes[dev].eof == 0) {
+ if (scsi_tapes[dev].buffer->buffer_bytes == 0 &&
+ scsi_tapes[dev].eof == 0) {
memset(cmd, 0, 10);
cmd[0] = READ_6;
@@ -734,6 +741,7 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );
scsi_tapes[dev].buffer->read_pointer = 0;
+ scsi_tapes[dev].eof_hit = 0;
if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) {
#ifdef DEBUG
@@ -796,8 +804,10 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
}
}
else
- scsi_tapes[dev].buffer->buffer_bytes = scsi_tapes[dev].buffer->buffer_size;
- } /* if (SCpnt->result != 0 || SCpnt->sense_buffer[0] != 0) */
+ scsi_tapes[dev].buffer->buffer_bytes =
+ scsi_tapes[dev].buffer->buffer_size;
+ } /* if (scsi_tapes[dev].buffer->buffer_bytes == 0 &&
+ scsi_tapes[dev].eof == 0) */
if (scsi_tapes[dev].buffer->buffer_bytes > 0) {
#ifdef DEBUG
@@ -818,10 +828,11 @@ int st_read(struct inode * inode, struct file * filp, char * buf, int count)
else if (scsi_tapes[dev].eof) {
scsi_tapes[dev].eof_hit = 1;
SCpnt->request.dev = -1; /* Mark as not busy */
- if (total)
- return total;
- else
+ if (total == 0 && scsi_tapes[dev].eof == 1)
+ scsi_tapes[dev].eof = 0;
+ if (total == 0 && scsi_tapes[dev].eof == 2)
return (-EIO);
+ return total;
}
} /* for (total = 0; total < count; ) */
@@ -956,7 +967,7 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
cmd[0] = SPACE;
cmd[1] = 3;
#ifdef DEBUG
- printk("st%d: Spacing to end of tape media.\n", dev);
+ printk("st%d: Spacing to end of recorded medium.\n", dev);
#endif
break;
case MTERASE:
@@ -1050,6 +1061,8 @@ static int st_int_ioctl(struct inode * inode,struct file * file,
if (!ioctl_result) {
if (cmd_in == MTBSFM)
ioctl_result = st_int_ioctl(inode, file, MTFSF, 1);
+ else if (cmd_in == MTFSFM)
+ ioctl_result = st_int_ioctl(inode, file, MTBSF, 1);
else if (cmd_in == MTSETBLK) {
scsi_tapes[dev].block_size = arg;
scsi_tapes[dev].buffer->buffer_blocks =
diff --git a/kernel/blk_drv/scsi/st.h b/kernel/blk_drv/scsi/st.h
index e5c9b7b..1df386c 100644
--- a/kernel/blk_drv/scsi/st.h
+++ b/kernel/blk_drv/scsi/st.h
@@ -27,10 +27,10 @@ typedef struct {
Scsi_Device* device;
unsigned dirty:1;
unsigned rw:2;
- unsigned eof:1;
+ unsigned eof:2;
unsigned write_prot:1;
unsigned in_use:1;
- unsigned eof_hit:2;
+ unsigned eof_hit:1;
ST_buffer * buffer;
int block_size;
int min_block;
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index a3b5f96..2d377ef 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -170,7 +170,10 @@ static int console_blanked = 0;
#define halfcolor (vc_cons[currcons].vc_halfcolor)
#define kbdmode (vc_cons[currcons].vc_kbdmode)
#define tab_stop (vc_cons[currcons].vc_tab_stop)
+#define vcmode (vt_cons[currcons].vc_mode)
#define vtmode (vt_cons[currcons].vt_mode)
+#define vtpid (vt_cons[currcons].vt_pid)
+#define vtnewvt (vt_cons[currcons].vt_newvt)
#define set_kbd(x) set_vc_kbd_flag(kbd_table+currcons,x)
#define clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x)
@@ -285,7 +288,7 @@ static void set_origin(int currcons)
{
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
return;
- if (currcons != fg_console || console_blanked || vtmode == KD_GRAPHICS)
+ if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
return;
cli();
outb_p(12, video_port_reg);
@@ -1194,7 +1197,7 @@ void con_write(struct tty_struct * tty)
state = ESnormal;
}
}
- if (vtmode == KD_GRAPHICS)
+ if (vcmode == KD_GRAPHICS)
return;
set_cursor(currcons);
}
@@ -1203,7 +1206,7 @@ void do_keyboard_interrupt(void)
{
TTY_READ_FLUSH(TTY_TABLE(0));
timer_active &= ~(1<<BLANK_TIMER);
- if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+ if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return;
if (console_blanked) {
timer_table[BLANK_TIMER].expires = 0;
@@ -1311,7 +1314,14 @@ long con_init(long kmem_start)
pos = origin = video_mem_start = base;
scr_end = video_mem_end = (base += screen_size);
vc_scrbuf[currcons] = (unsigned short *) origin;
- vtmode = KD_TEXT;
+ vcmode = KD_TEXT;
+ vtmode.mode = VT_AUTO;
+ vtmode.waitv = 0;
+ vtmode.relsig = 0;
+ vtmode.acqsig = 0;
+ vtmode.frsig = 0;
+ vtpid = -1;
+ vtnewvt = -1;
clr_kbd(kbdraw);
def_color = 0x07; /* white */
ulcolor = 0x0f; /* bold white */
@@ -1360,6 +1370,8 @@ static void set_scrmem(int currcons)
void blank_screen(void)
{
+ if (console_blanked)
+ return;
timer_table[BLANK_TIMER].fn = unblank_screen;
get_scrmem(fg_console);
hide_cursor(fg_console);
@@ -1369,6 +1381,8 @@ void blank_screen(void)
void unblank_screen(void)
{
+ if (!console_blanked)
+ return;
timer_table[BLANK_TIMER].fn = blank_screen;
if (blankinterval) {
timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
@@ -1463,7 +1477,7 @@ void console_print(const char * b)
pos+=2;
}
set_cursor(currcons);
- if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+ if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
return;
timer_active &= ~(1<<BLANK_TIMER);
if (console_blanked) {
@@ -1483,5 +1497,7 @@ int con_open(struct tty_struct *tty, struct file * filp)
{
tty->write = con_write;
tty->ioctl = vt_ioctl;
+ if (tty->line > NR_CONSOLES)
+ return -ENODEV;
return 0;
}
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index 73a71e9..5f43db0 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -32,6 +32,8 @@ extern void ctrl_alt_del(void);
extern void change_console(unsigned int new_console);
unsigned long kbd_flags = 0;
+unsigned long kbd_dead_keys = 0;
+unsigned long kbd_prev_dead_keys = 0;
struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table;
@@ -54,59 +56,54 @@ static struct pt_regs * pt_regs;
static void keyboard_interrupt(int int_pt_regs)
{
static unsigned char rep = 0xff;
- unsigned char scancode, x;
+ unsigned char scancode;
pt_regs = (struct pt_regs *) int_pt_regs;
- scancode=inb_p(0x60);
- x=inb_p(0x61);
- outb_p(x|0x80, 0x61);
- outb_p(x&0x7f, 0x61);
- if (scancode == 0xe0)
- set_kbd_flag(KG_E0);
- else if (scancode == 0xe1)
- set_kbd_flag(KG_E1);
- tty = TTY_TABLE(0);
- kbd = kbd_table + fg_console;
- if (vc_kbd_flag(kbd,VC_RAW)) {
- kbd_flags = 0;
- put_queue(scancode);
- do_keyboard_interrupt();
- return;
- }
- if (scancode == 0xe0 || scancode == 0xe1)
- return;
- /*
- * The keyboard maintains its own internal caps lock and num lock
- * statuses. In caps lock mode E0 AA precedes make code and E0 2A
- * follows break code. In num lock mode, E0 2A precedes make
- * code and E0 AA follows break code. We do our own book-keeping,
- * so we will just ignore these.
- */
- if (kbd_flag(KG_E0) && (scancode == 0x2a || scancode == 0xaa)) {
- clr_kbd_flag(KG_E0);
- clr_kbd_flag(KG_E1);
- return;
- }
- /*
- * Repeat a key only if the input buffers are empty or the
- * characters get echoed locally. This makes key repeat usable
- * with slow applications and unders heavy loads.
- */
- if (scancode == rep) {
- if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
- (L_ECHO(tty) ||
- (EMPTY(&tty->secondary) &&
- EMPTY(&tty->read_q))))) {
- clr_kbd_flag(KG_E0);
- clr_kbd_flag(KG_E1);
- return;
+ while (inb_p(0x64) & 1) {
+ kbd_prev_dead_keys |= kbd_dead_keys;
+ if (!kbd_dead_keys)
+ kbd_prev_dead_keys = 0;
+ kbd_dead_keys = 0;
+ scancode = inb_p(0x60);
+ tty = TTY_TABLE(0);
+ kbd = kbd_table + fg_console;
+ if (vc_kbd_flag(kbd,VC_RAW)) {
+ kbd_flags = 0;
+ put_queue(scancode);
+ continue;
+ }
+ if (scancode == 0xe0) {
+ set_kbd_dead(KGD_E0);
+ continue;
+ } else if (scancode == 0xe1) {
+ set_kbd_dead(KGD_E1);
+ continue;
}
+ /*
+ * The keyboard maintains its own internal caps lock and num lock
+ * statuses. In caps lock mode E0 AA precedes make code and E0 2A
+ * follows break code. In num lock mode, E0 2A precedes make
+ * code and E0 AA follows break code. We do our own book-keeping,
+ * so we will just ignore these.
+ */
+ if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa))
+ continue;
+ /*
+ * Repeat a key only if the input buffers are empty or the
+ * characters get echoed locally. This makes key repeat usable
+ * with slow applications and unders heavy loads.
+ */
+ if (scancode == rep) {
+ if (!(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
+ (L_ECHO(tty) ||
+ (EMPTY(&tty->secondary) &&
+ EMPTY(&tty->read_q)))))
+ continue;
+ }
+ rep = scancode;
+ key_table[scancode](scancode);
}
- rep = scancode;
- key_table[scancode](scancode);
do_keyboard_interrupt();
- clr_kbd_flag(KG_E0);
- clr_kbd_flag(KG_E1);
}
static void put_queue(int ch)
@@ -147,7 +144,7 @@ static void puts_queue(char *cp)
static void ctrl(int sc)
{
- if (kbd_flag(KG_E0))
+ if (kbd_dead(KGD_E0))
set_kbd_flag(KG_RCTRL);
else
set_kbd_flag(KG_LCTRL);
@@ -155,7 +152,7 @@ static void ctrl(int sc)
static void alt(int sc)
{
- if (kbd_flag(KG_E0))
+ if (kbd_dead(KGD_E0))
set_kbd_flag(KG_ALTGR);
else
set_kbd_flag(KG_ALT);
@@ -163,7 +160,7 @@ static void alt(int sc)
static void unctrl(int sc)
{
- if (kbd_flag(KG_E0))
+ if (kbd_dead(KGD_E0))
clr_kbd_flag(KG_RCTRL);
else
clr_kbd_flag(KG_LCTRL);
@@ -171,7 +168,7 @@ static void unctrl(int sc)
static void unalt(int sc)
{
- if (kbd_flag(KG_E0))
+ if (kbd_dead(KGD_E0))
clr_kbd_flag(KG_ALTGR);
else {
clr_kbd_flag(KG_ALT);
@@ -218,6 +215,8 @@ static void uncaps(int sc)
static void show_ptregs(void)
{
+ if (!pt_regs)
+ return;
printk("\nEIP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
if (pt_regs->cs & 3)
printk(" ESP: %04x:%08x",0xffff & pt_regs->cs,pt_regs->eip);
@@ -1167,7 +1166,7 @@ static void cursor(int sc)
ctrl_alt_del();
return;
}
- if (kbd_flag(KG_E0)) {
+ if (kbd_dead(KGD_E0)) {
cur(sc);
return;
}
@@ -1226,7 +1225,7 @@ static void func(int sc)
static void slash(int sc)
{
- if (!kbd_flag(KG_E0))
+ if (!kbd_dead(KGD_E0))
do_self(sc);
else if (vc_kbd_flag(kbd,VC_APPLIC))
applkey('Q');
@@ -1244,7 +1243,7 @@ static void star(int sc)
static void enter(int sc)
{
- if (kbd_flag(KG_E0) && vc_kbd_flag(kbd,VC_APPLIC))
+ if (kbd_dead(KGD_E0) && vc_kbd_flag(kbd,VC_APPLIC))
applkey('M');
else {
put_queue(13);
@@ -1418,7 +1417,6 @@ static fptr key_table[] = {
unsigned long kbd_init(unsigned long kmem_start)
{
int i;
- unsigned char a;
struct kbd_struct * kbd;
kbd = kbd_table + 0;
@@ -1428,8 +1426,6 @@ unsigned long kbd_init(unsigned long kmem_start)
kbd->kbd_flags = KBDFLAGS;
}
request_irq(KEYBOARD_IRQ,keyboard_interrupt);
- a=inb_p(0x61);
- outb_p(a|0x80,0x61);
- outb_p(a,0x61);
+ keyboard_interrupt(0);
return kmem_start;
}
diff --git a/kernel/chr_drv/psaux.c b/kernel/chr_drv/psaux.c
index 2eb51bf..3dc5a26 100644
--- a/kernel/chr_drv/psaux.c
+++ b/kernel/chr_drv/psaux.c
@@ -160,8 +160,9 @@ static void aux_interrupt(int cpl)
static void release_aux(struct inode * inode, struct file * file)
{
poll_status();
- outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */
+ poll_status();
+ outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
free_irq(AUX_IRQ);
aux_busy = 0;
@@ -288,6 +289,9 @@ unsigned long psaux_init(unsigned long kmem_start)
queue->head = queue->tail = 0;
queue->proc_list = NULL;
aux_present = 1;
+ poll_status();
+ outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
+ aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
return kmem_start;
}
diff --git a/kernel/chr_drv/pty.c b/kernel/chr_drv/pty.c
index 46221e9..6b08ab0 100644
--- a/kernel/chr_drv/pty.c
+++ b/kernel/chr_drv/pty.c
@@ -28,10 +28,8 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (!tty->link)
return;
wake_up_interruptible(&tty->link->write_q.proc_list);
- if (IS_A_PTY_MASTER(tty->line)) {
- if (tty->link->session > 0)
- kill_sl(tty->link->session,SIGHUP,1);
- }
+ if (IS_A_PTY_MASTER(tty->line))
+ tty_hangup(tty->link);
}
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index 5a4ac26..8ce18ed 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -59,7 +59,7 @@
*
*/
-#define NEW_INTERRUPT_ROUTINE
+#undef NEW_INTERRUPT_ROUTINE
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
@@ -401,9 +401,8 @@ static void modem_status_intr(struct async_struct * info)
unsigned char status = inb(UART_MSR + info->port);
if (!(info->tty->termios->c_cflag & CLOCAL)) {
- if (((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD)
- && info->tty->session > 0)
- kill_sl(info->tty->session,SIGHUP,1);
+ if ((status & (UART_MSR_DCD|UART_MSR_DDCD)) == UART_MSR_DDCD)
+ tty_hangup(info->tty);
if (info->tty->termios->c_cflag & CRTSCTS)
info->tty->stopped = !(status & UART_MSR_CTS);
@@ -523,10 +522,8 @@ static void rs_timer(void)
if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
wake_up_interruptible(&info->tty->write_q.proc_list);
}
- if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event)) {
- if (info->tty->session > 0)
- kill_sl(info->tty->session,SIGHUP,1);
- }
+ if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event))
+ tty_hangup(info->tty);
if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) {
flush_input(info->tty);
flush_output(info->tty);
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 2e7b4c3..00e4952 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -28,6 +28,7 @@
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/tty.h>
+#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/kd.h>
#include <linux/mm.h>
@@ -54,6 +55,11 @@ struct tty_struct * redirect = NULL;
struct wait_queue * keypress_wait = NULL;
static int initialize_tty_struct(struct tty_struct *tty, int line);
+static int tty_read(struct inode *, struct file *, char *, int);
+static int tty_write(struct inode *, struct file *, char *, int);
+static int tty_select(struct inode *, struct file *, int, select_table *);
+static int tty_open(struct inode *, struct file *);
+static void tty_release(struct inode *, struct file *);
void put_tty_queue(char c, struct tty_queue * queue)
{
@@ -105,13 +111,228 @@ void tty_read_flush(struct tty_struct * tty)
printk("tty_read_flush: bit already cleared\n");
}
-void change_console(unsigned int new_console)
+static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count)
+{
+ return 0;
+}
+
+static int hung_up_tty_write(struct inode * inode, struct file * file, char * buf, int count)
+{
+ return -EIO;
+}
+
+static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+{
+ return 1;
+}
+
+static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
+{
+ return -EBADF;
+}
+
+static struct file_operations tty_fops = {
+ tty_lseek,
+ tty_read,
+ tty_write,
+ NULL, /* tty_readdir */
+ tty_select,
+ tty_ioctl,
+ NULL, /* tty_mmap */
+ tty_open,
+ tty_release
+};
+
+static struct file_operations hung_up_tty_fops = {
+ tty_lseek,
+ hung_up_tty_read,
+ hung_up_tty_write,
+ NULL, /* hung_up_tty_readdir */
+ hung_up_tty_select,
+ tty_ioctl,
+ NULL, /* hung_up_tty_mmap */
+ tty_open,
+ tty_release
+};
+
+void tty_hangup(struct tty_struct * tty)
{
- if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
+ struct file * filp;
+ int dev;
+
+ if (!tty)
return;
+ dev = 0x0400 + tty->line;
+ filp = file_table + NR_FILE;
+ while (filp-- > file_table) {
+ if (!filp->f_count)
+ continue;
+ if (filp->f_rdev != dev)
+ continue;
+ if (filp->f_op != &tty_fops)
+ continue;
+ filp->f_op = &hung_up_tty_fops;
+ }
+ wake_up_interruptible(&tty->secondary.proc_list);
+ wake_up_interruptible(&tty->read_q.proc_list);
+ wake_up_interruptible(&tty->write_q.proc_list);
+ if (tty->session > 0)
+ kill_sl(tty->session,SIGHUP,1);
+}
+
+static inline int hung_up(struct file * filp)
+{
+ return filp->f_op == &hung_up_tty_fops;
+}
+
+extern int kill_proc(int pid, int sig, int priv);
+
+/*
+ * Performs the back end of a vt switch
+ */
+void complete_change_console(unsigned int new_console)
+{
+ unsigned char old_vc_mode;
+
if (new_console == fg_console || new_console >= NR_CONSOLES)
return;
+
+ /*
+ * If we're switching, we could be going from KD_GRAPHICS to
+ * KD_TEXT mode or vice versa, which means we need to blank or
+ * unblank the screen later.
+ */
+ old_vc_mode = vt_cons[fg_console].vc_mode;
update_screen(new_console);
+
+ /*
+ * If this new console is under process control, send it a signal
+ * telling it that it has acquired. Also check if it has died and
+ * clean up (similar to logic employed in change_console())
+ */
+ if (vt_cons[new_console].vt_mode.mode == VT_PROCESS)
+ {
+ /*
+ * Send the signal as privileged - kill_proc() will
+ * tell us if the process has gone or something else
+ * is awry
+ */
+ if (kill_proc(vt_cons[new_console].vt_pid,
+ vt_cons[new_console].vt_mode.acqsig,
+ 1) != 0)
+ {
+ /*
+ * The controlling process has died, so we revert back to
+ * normal operation. In this case, we'll also change back
+ * to KD_TEXT mode. I'm not sure if this is strictly correct
+ * but it saves the agony when the X server dies and the screen
+ * remains blanked due to KD_GRAPHICS! It would be nice to do
+ * this outside of VT_PROCESS but there is no single process
+ * to account for and tracking tty count may be undesirable.
+ */
+ vt_cons[new_console].vc_mode = KD_TEXT;
+ clr_vc_kbd_flag(kbd_table + new_console, VC_RAW);
+ vt_cons[new_console].vt_mode.mode = VT_AUTO;
+ vt_cons[new_console].vt_mode.waitv = 0;
+ vt_cons[new_console].vt_mode.relsig = 0;
+ vt_cons[new_console].vt_mode.acqsig = 0;
+ vt_cons[new_console].vt_mode.frsig = 0;
+ vt_cons[new_console].vt_pid = -1;
+ vt_cons[new_console].vt_newvt = -1;
+ }
+ }
+
+ /*
+ * We do this here because the controlling process above may have
+ * gone, and so there is now a new vc_mode
+ */
+ if (old_vc_mode != vt_cons[new_console].vc_mode)
+ {
+ if (vt_cons[new_console].vc_mode == KD_TEXT)
+ unblank_screen();
+ else
+ {
+ timer_active &= ~(1<<BLANK_TIMER);
+ blank_screen();
+ }
+ }
+
+ return;
+}
+
+/*
+ * Performs the front-end of a vt switch
+ */
+void change_console(unsigned int new_console)
+{
+ if (new_console == fg_console || new_console >= NR_CONSOLES)
+ return;
+
+ /*
+ * If this vt is in process mode, then we need to handshake with
+ * that process before switching. Essentially, we store where that
+ * vt wants to switch to and wait for it to tell us when it's done
+ * (via VT_RELDISP ioctl).
+ *
+ * We also check to see if the controlling process still exists.
+ * If it doesn't, we reset this vt to auto mode and continue.
+ * This is a cheap way to track process control. The worst thing
+ * that can happen is: we send a signal to a process, it dies, and
+ * the switch gets "lost" waiting for a response; hopefully, the
+ * user will try again, we'll detect the process is gone (unless
+ * the user waits just the right amount of time :-) and revert the
+ * vt to auto control.
+ */
+ if (vt_cons[fg_console].vt_mode.mode == VT_PROCESS)
+ {
+ /*
+ * Send the signal as privileged - kill_proc() will
+ * tell us if the process has gone or something else
+ * is awry
+ */
+ if (kill_proc(vt_cons[fg_console].vt_pid,
+ vt_cons[fg_console].vt_mode.relsig,
+ 1) == 0)
+ {
+ /*
+ * It worked. Mark the vt to switch to and
+ * return. The process needs to send us a
+ * VT_RELDISP ioctl to complete the switch.
+ */
+ vt_cons[fg_console].vt_newvt = new_console;
+ return;
+ }
+
+ /*
+ * The controlling process has died, so we revert back to
+ * normal operation. In this case, we'll also change back
+ * to KD_TEXT mode. I'm not sure if this is strictly correct
+ * but it saves the agony when the X server dies and the screen
+ * remains blanked due to KD_GRAPHICS! It would be nice to do
+ * this outside of VT_PROCESS but there is no single process
+ * to account for and tracking tty count may be undesirable.
+ */
+ vt_cons[fg_console].vc_mode = KD_TEXT;
+ clr_vc_kbd_flag(kbd_table + fg_console, VC_RAW);
+ vt_cons[fg_console].vt_mode.mode = VT_AUTO;
+ vt_cons[fg_console].vt_mode.waitv = 0;
+ vt_cons[fg_console].vt_mode.relsig = 0;
+ vt_cons[fg_console].vt_mode.acqsig = 0;
+ vt_cons[fg_console].vt_mode.frsig = 0;
+ vt_cons[fg_console].vt_pid = -1;
+ vt_cons[fg_console].vt_newvt = -1;
+ /*
+ * Fall through to normal (VT_AUTO) handling of the switch...
+ */
+ }
+
+ /*
+ * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
+ */
+ if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
+ return;
+
+ complete_change_console(new_console);
}
void wait_for_keypress(void)
@@ -272,14 +493,14 @@ int is_ignored(int sig)
}
static int available_canon_input(struct tty_struct *);
-static void __wait_for_canon_input(struct tty_struct *);
+static void __wait_for_canon_input(struct file * file, struct tty_struct *);
-static void wait_for_canon_input(struct tty_struct * tty)
+static void wait_for_canon_input(struct file * file, struct tty_struct * tty)
{
if (!available_canon_input(tty)) {
if (current->signal & ~current->blocked)
return;
- __wait_for_canon_input(tty);
+ __wait_for_canon_input(file, tty);
}
}
@@ -313,7 +534,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
return -EAGAIN;
}
} else if (L_CANON(tty)) {
- wait_for_canon_input(tty);
+ wait_for_canon_input(file, tty);
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
}
@@ -374,6 +595,8 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
TTY_WRITE_FLUSH(tty->link);
if (!EMPTY(&tty->secondary))
continue;
+ if (hung_up(file))
+ break;
current->state = TASK_INTERRUPTIBLE;
if (EMPTY(&tty->secondary))
schedule();
@@ -402,7 +625,7 @@ static int read_chan(struct tty_struct * tty, struct file * file, char * buf, in
return 0;
}
-static void __wait_for_canon_input(struct tty_struct * tty)
+static void __wait_for_canon_input(struct file * file, struct tty_struct * tty)
{
struct wait_queue wait = { current, NULL };
@@ -413,6 +636,8 @@ static void __wait_for_canon_input(struct tty_struct * tty)
break;
if (current->signal & ~current->blocked)
break;
+ if (hung_up(file))
+ break;
schedule();
}
current->state = TASK_RUNNING;
@@ -447,6 +672,8 @@ static int write_chan(struct tty_struct * tty, struct file * file, char * buf, i
while (nr>0) {
if (current->signal & ~current->blocked)
break;
+ if (hung_up(file))
+ break;
if (tty->link && !tty->link->count) {
send_sig(SIGPIPE,current,0);
break;
@@ -524,25 +751,25 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
{
- int dev,i;
+ int dev, i, is_console;
struct tty_struct * tty;
dev = file->f_rdev;
+ is_console = (inode->i_rdev == 0x0400);
if (MAJOR(dev) != 4) {
printk("tty_write: pseudo-major != 4\n");
return -EINVAL;
}
dev = MINOR(dev);
- if (redirect && ((dev == 0) || (dev == fg_console+1)))
+ if (is_console && redirect)
tty = redirect;
else
tty = TTY_TABLE(dev);
if (!tty || !tty->write)
return -EIO;
- if (MINOR(inode->i_rdev) &&
- L_TOSTOP(tty) && (tty->pgrp > 0) &&
+ if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == dev) && (tty->pgrp != current->pgrp)) {
- if (is_orphaned_pgrp(tty->pgrp))
+ if (is_orphaned_pgrp(current->pgrp))
return -EIO;
if (!is_ignored(SIGTTOU)) {
(void) kill_pg(current->pgrp, SIGTTOU, 1);
@@ -555,11 +782,6 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
return i;
}
-static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
-{
- return -EBADF;
-}
-
/*
* tty_open and tty_release keep up the tty count that contains the
* number of opens done on a tty. We cannot use the inode-count, as
@@ -803,18 +1025,6 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se
return 0;
}
-static struct file_operations tty_fops = {
- tty_lseek,
- tty_read,
- tty_write,
- NULL, /* tty_readdir */
- tty_select,
- tty_ioctl,
- NULL, /* tty_mmap */
- tty_open,
- tty_release
-};
-
/*
* This implements the "Secure Attention Key" --- the idea is to
* prevent trojan horses by killing all processes associated with this
@@ -920,9 +1130,9 @@ long tty_init(long kmem_start)
tty_table[i] = 0;
tty_termios[i] = 0;
}
- kmem_start = kbd_init(kmem_start);
kmem_start = con_init(kmem_start);
kmem_start = rs_init(kmem_start);
+ kmem_start = kbd_init(kmem_start);
printk("%d virtual consoles\n\r",NR_CONSOLES);
return kmem_start;
}
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index 02e7203..7021f2e 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -386,16 +386,22 @@ int tty_ioctl(struct inode * inode, struct file * file,
return -EINVAL;
}
case TIOCCONS:
- if (!IS_A_PTY(dev))
- return -EINVAL;
+ if (IS_A_CONSOLE(dev)) {
+ if (!suser())
+ return -EPERM;
+ redirect = NULL;
+ return 0;
+ }
if (redirect)
return -EBUSY;
if (!suser())
return -EPERM;
if (IS_A_PTY_MASTER(dev))
redirect = other_tty;
- else
+ else if (IS_A_PTY_SLAVE(dev))
redirect = tty;
+ else
+ return -EINVAL;
return 0;
case FIONBIO:
arg = get_fs_long((unsigned long *) arg);
diff --git a/kernel/chr_drv/vt.c b/kernel/chr_drv/vt.c
index b319734..5879b8e 100644
--- a/kernel/chr_drv/vt.c
+++ b/kernel/chr_drv/vt.c
@@ -20,13 +20,24 @@
#include "vt_kern.h"
/*
- * console (vt and kd) routines, as defined by usl svr4 manual
+ * Console (vt and kd) routines, as defined by USL SVR4 manual
+ *
+ * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
+ * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
+ * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
+ * always treat our set of vt as numbered 1..NR_CONSOLES (corresponding to
+ * ttys 0..NR_CONSOLES-1).
+ *
+ * Mostly done for X386, but with some slight differences and omissions.
+ * Should be useable by other SYSV programs in the future.
*/
struct vt_cons vt_cons[NR_CONSOLES];
extern int sys_ioperm(unsigned long from, unsigned long num, int on);
extern void set_leds(void);
+extern void change_console(unsigned int new_console);
+extern void complete_change_console(unsigned int new_console);
/*
* these are the valid i/o ports we're allowed to change. they map all the
@@ -37,26 +48,53 @@ extern void set_leds(void);
#define GPNUM (GPLAST - GPFIRST + 1)
/*
- * turns on sound of some freq. 0 turns it off.
- * stolen from console.c, so i'm not sure if its the correct interpretation
+ * Generates sound of some count for some number of clock ticks
+ * [count = 1193180 / frequency]
+ *
+ * If freq is 0, will turn off sound, else will turn it on for that time.
+ * If msec is 0, will return immediately, else will sleep for msec time, then
+ * turn sound off.
+ *
+ * We use the BEEP_TIMER vector since we're using the same method to
+ * generate sound, and we'll overwrite any beep in progress. That may
+ * be something to fix later, if we like.
+ *
+ * We also return immediately, which is what was implied within the X
+ * comments - KDMKTONE doesn't put the process to sleep.
*/
-static int
-kiocsound(unsigned int freq)
+void
+kd_nosound(void)
{
- if (freq == 0) {
- /* disable counter 2 */
- outb(inb_p(0x61)&0xFC, 0x61);
- }
- else {
+ /* disable counter 2 */
+ outb(inb_p(0x61)&0xFC, 0x61);
+ return;
+}
+
+void
+kd_mksound(unsigned int count, unsigned int ticks)
+{
+ if (count)
+ {
/* enable counter 2 */
outb_p(inb_p(0x61)|3, 0x61);
/* set command for counter 2, 2 byte write */
outb_p(0xB6, 0x43);
/* select desired HZ */
- outb_p(freq & 0xff, 0x42);
- outb((freq >> 8) & 0xff, 0x42);
+ outb_p(count & 0xff, 0x42);
+ outb((count >> 8) & 0xff, 0x42);
+
+ if (ticks)
+ {
+ timer_table[BEEP_TIMER].expires = jiffies + ticks;
+ timer_table[BEEP_TIMER].fn = kd_nosound;
+ timer_active |= (1 << BEEP_TIMER);
+ }
}
- return 0;
+
+ else
+ kd_nosound();
+
+ return;
}
/*
@@ -66,7 +104,7 @@ kiocsound(unsigned int freq)
int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned int arg)
{
- int console;
+ int console, i;
unsigned char ucval;
struct kbd_struct * kbd;
@@ -78,7 +116,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd = kbd_table + console;
switch (cmd) {
case KIOCSOUND:
- return kiocsound((unsigned int)arg);
+ kd_mksound((unsigned int)arg, 0);
+ return 0;
+
+ case KDMKTONE:
+ {
+ unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+
+ /*
+ * Generate the tone for the appropriate number of ticks.
+ * If the time is zero, turn off sound ourselves.
+ */
+ kd_mksound(arg & 0xffff, ticks);
+ if (ticks == 0)
+ kd_nosound();
+ return 0;
+ }
case KDGKBTYPE:
/*
@@ -120,21 +173,25 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
default:
return -EINVAL;
}
- if (vt_cons[console].vt_mode == (unsigned char) arg)
+ if (vt_cons[console].vc_mode == (unsigned char) arg)
return 0;
- vt_cons[console].vt_mode = (unsigned char) arg;
+ vt_cons[console].vc_mode = (unsigned char) arg;
if (console != fg_console)
return 0;
+ /*
+ * explicitly blank/unblank the screen if switching modes
+ */
if (arg == KD_TEXT)
unblank_screen();
else {
- timer_active &= 1<<BLANK_TIMER;
+ timer_active &= ~(1<<BLANK_TIMER);
blank_screen();
}
return 0;
+
case KDGETMODE:
verify_area((void *) arg, sizeof(unsigned long));
- put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg);
+ put_fs_long(vt_cons[console].vc_mode, (unsigned long *) arg);
return 0;
case KDMAPDISP:
@@ -155,6 +212,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EINVAL;
flush_input(tty);
return 0;
+
case KDGKBMODE:
verify_area((void *) arg, sizeof(unsigned long));
ucval = vc_kbd_flag(kbd, VC_RAW);
@@ -172,6 +230,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ucval |= LED_CAP;
put_fs_byte(ucval, (unsigned char *) arg);
return 0;
+
case KDSETLED:
if (arg & ~7)
return -EINVAL;
@@ -190,6 +249,95 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
set_leds();
return 0;
+ case VT_SETMODE:
+ {
+ struct vt_mode *vtmode = (struct vt_mode *)arg;
+ char mode;
+
+ verify_area((void *)vtmode, sizeof(struct vt_mode));
+ mode = get_fs_byte(&vtmode->mode);
+ if (mode != VT_AUTO && mode != VT_PROCESS)
+ return -EINVAL;
+ vt_cons[console].vt_mode.mode = mode;
+ vt_cons[console].vt_mode.waitv = get_fs_byte(&vtmode->waitv);
+ vt_cons[console].vt_mode.relsig = get_fs_word(&vtmode->relsig);
+ vt_cons[console].vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
+ /* the frsig is ignored, so we set it to 0 */
+ vt_cons[console].vt_mode.frsig = 0;
+ vt_cons[console].vt_pid = current->pid;
+ vt_cons[console].vt_newvt = 0;
+ return 0;
+ }
+
+ case VT_GETMODE:
+ {
+ struct vt_mode *vtmode = (struct vt_mode *)arg;
+
+ verify_area((void *)arg, sizeof(struct vt_mode));
+ put_fs_byte(vt_cons[console].vt_mode.mode, &vtmode->mode);
+ put_fs_byte(vt_cons[console].vt_mode.waitv, &vtmode->waitv);
+ put_fs_word(vt_cons[console].vt_mode.relsig, &vtmode->relsig);
+ put_fs_word(vt_cons[console].vt_mode.acqsig, &vtmode->acqsig);
+ put_fs_word(vt_cons[console].vt_mode.frsig, &vtmode->frsig);
+ return 0;
+ }
+
+ /*
+ * Returns the first available (non-opened) console.
+ */
+ case VT_OPENQRY:
+ verify_area((void *) arg, sizeof(long));
+ for (i = 1; i <= NR_CONSOLES; ++i)
+ if (!tty_table[i] || tty_table[i]->count == 0)
+ break;
+ put_fs_long(i <= NR_CONSOLES ? i : -1, (unsigned long *)arg);
+ return 0;
+
+ /*
+ * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
+ * with num >= 1 (switches to vt 0, our console) are not allowed, just
+ * to preserve sanity.
+ */
+ case VT_ACTIVATE:
+ if (arg == 0 || arg > NR_CONSOLES)
+ return -ENXIO;
+ change_console(arg - 1);
+ return 0;
+
+ /*
+ * If a vt is under process control, the kernel will not switch to it
+ * immediately, but postpone the operation until the process calls this
+ * ioctl, allowing the switch to complete.
+ *
+ * XXX Under X, the switching code calls VT_RELDISP with an arg of 2
+ * when it has switched back to it's vt. That's not kosher according
+ * to my documentation, which says this is only called when releasing
+ * the vt under your control.
+ */
+ case VT_RELDISP:
+ if (vt_cons[console].vt_mode.mode != VT_PROCESS ||
+ vt_cons[console].vt_newvt < 0)
+ return -EINVAL;
+
+ if (arg != 0)
+ {
+ /*
+ * If arg is nonzero, the current vt has been released,
+ * so we can go ahead and complete the switch.
+ */
+ int newvt = vt_cons[console].vt_newvt;
+ vt_cons[console].vt_newvt = -1;
+ complete_change_console(newvt);
+ }
+ else
+ {
+ /*
+ * Mark that we've performed our part and return.
+ */
+ vt_cons[console].vt_newvt = -1;
+ }
+ return 0;
+
default:
return -EINVAL;
}
diff --git a/kernel/chr_drv/vt_kern.h b/kernel/chr_drv/vt_kern.h
index 5d72a3a..7df7f9f 100644
--- a/kernel/chr_drv/vt_kern.h
+++ b/kernel/chr_drv/vt_kern.h
@@ -5,11 +5,17 @@
* this really is an extension of the vc_cons structure in console.c, but
* with information needed by the vt package
*/
+
+#include <linux/vt.h>
+
extern struct vt_cons {
- int vt_mode; /* KD_TEXT, ... */
+ unsigned char vc_mode; /* KD_TEXT, ... */
unsigned char vc_kbdraw;
unsigned char vc_kbde0;
unsigned char vc_kbdleds;
+ struct vt_mode vt_mode;
+ int vt_pid;
+ int vt_newvt;
} vt_cons[NR_CONSOLES];
#endif /* _VT_KERN_H */
diff --git a/kernel/fork.c b/kernel/fork.c
index d7ff3cd..b5b8f21 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -31,7 +31,6 @@ void verify_area(void * addr,int size)
start = (unsigned long) addr;
size += start & 0xfff;
start &= 0xfffff000;
- start += get_base(current->ldt[2]);
while (size>0) {
size -= 4096;
write_verify(start);
@@ -39,31 +38,6 @@ void verify_area(void * addr,int size)
}
}
-int copy_mem(int nr,struct task_struct * p)
-{
- unsigned long old_data_base,new_data_base,data_limit;
- unsigned long old_code_base,new_code_base,code_limit;
-
- code_limit = get_limit(0x0f);
- data_limit = get_limit(0x17);
- old_code_base = get_base(current->ldt[1]);
- old_data_base = get_base(current->ldt[2]);
- if (old_data_base != old_code_base) {
- printk("ldt[0]: %08x %08x\n",current->ldt[0].a,current->ldt[0].b);
- printk("ldt[1]: %08x %08x\n",current->ldt[1].a,current->ldt[1].b);
- printk("ldt[2]: %08x %08x\n",current->ldt[2].a,current->ldt[2].b);
- panic("We don't support separate I&D");
- }
- if (data_limit < code_limit)
- panic("Bad data_limit");
- new_data_base = old_data_base;
- new_code_base = old_code_base;
- p->start_code = new_code_base;
- set_base(p->ldt[1],new_code_base);
- set_base(p->ldt[2],new_data_base);
- return copy_page_tables(p);
-}
-
static int find_empty_process(void)
{
int i, task_nr;
@@ -163,7 +137,7 @@ int sys_fork(long ebx,long ecx,long edx,
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387));
p->kernel_stack_page = get_free_page(GFP_KERNEL);
- if (!p->kernel_stack_page || copy_mem(nr,p)) {
+ if (!p->kernel_stack_page || copy_page_tables(p)) {
task[nr] = NULL;
REMOVE_LINKS(p);
free_page(p->kernel_stack_page);
diff --git a/kernel/printk.c b/kernel/printk.c
index c555f9f..7cc2a56 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -64,7 +64,7 @@ int sys_syslog(int type, char * buf, int len)
sti();
}
i = 0;
- while (log_size && len) {
+ while (log_size && i < len) {
c = *((char *) log_page+log_start);
log_start++;
log_size--;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 52e0d41..5b08cff 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -229,6 +229,8 @@ int sys_ptrace(long request, long pid, long addr, long data)
current->flags |= PF_PTRACED;
return 0;
}
+ if (pid == 1) /* you may not mess with init */
+ return -EPERM;
if (!(child = get_task(pid)))
return -ESRCH;
if (request == PTRACE_ATTACH) {
diff --git a/net/Makefile b/net/Makefile
index b59d8d8..7b8672c 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -14,6 +14,7 @@ SUBDIRS = tcp
ifdef CONFIG_TCPIP
NET_SUBDIRS = tcp
+TCP_ARCHIVE = tcp/tcpip.a
endif
.c.o:
@@ -26,7 +27,7 @@ endif
OBJS = socket.o unix.o
net.o: $(OBJS) subdirs
- $(LD) -r -o net.o $(OBJS) tcp/tcpip.o
+ $(LD) -r -o net.o $(OBJS) $(TCP_ARCHIVE)
subdirs: dummy
@@ -40,8 +41,6 @@ dep:
$(CPP) -M *.c > .depend
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
-socket.o: Makefile
-
dummy:
#
diff --git a/net/tcp/Makefile b/net/tcp/Makefile
index b7695a3..faf3fdf 100644
--- a/net/tcp/Makefile
+++ b/net/tcp/Makefile
@@ -19,8 +19,8 @@
OBJS = sock.o tcp.o ip.o timer.o we.o arp.o udp.o eth.o Space.o loopback.o \
icmp.o protocols.o raw.o pack_type.o dev.o packet.o
-tcpip.o: $(OBJS)
- $(LD) -r -o tcpip.o $(OBJS)
+tcpip.a: $(OBJS)
+ $(AR) rcs tcpip.a $(OBJS)
subdirs: dummy
for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done
diff --git a/net/tcp/arp.c b/net/tcp/arp.c
index 7ca4205..c824f74 100644
--- a/net/tcp/arp.c
+++ b/net/tcp/arp.c
@@ -73,19 +73,16 @@ static void
send_arp_q(void)
{
struct sk_buff *skb;
- struct sk_buff *skb2;
+ struct sk_buff *next;
cli();
- if (arp_q == NULL) return;
-
- skb = arp_q;
- do {
+ next = arp_q;
+ arp_q = NULL;
+ sti();
+ while ((skb = next) != NULL) {
if (skb->magic != ARP_QUEUE_MAGIC)
{
- printk ("arp.c skb with bad magic - %X: squashing queue\n");
- cli();
- arp_q = NULL;
- sti();
+ printk ("arp.c skb with bad magic - %X: squashing queue\n", skb->magic);
return;
}
/* extra consistancy check. */
@@ -94,46 +91,54 @@ send_arp_q(void)
|| (unsigned long)(skb->next) > 16*1024*1024
#endif
)
-
{
printk ("dev.c: *** bug bad skb->next, squashing queue \n");
- cli();
- arp_q = NULL;
- sti();
return;
}
+ /* first remove skb from the queue. */
+ next = skb->next;
+ if (next == skb)
+ {
+ next = NULL;
+ }
+ else
+ {
+ skb->prev->next = next;
+ next->prev = skb->prev;
+ }
+
skb->magic = 0;
- skb2=skb->next;
+ skb->next = NULL;
+ skb->prev = NULL;
- sti();
if (!skb->dev->rebuild_header (skb+1, skb->dev))
{
- cli();
- if (skb->next == skb)
- {
- arp_q = NULL;
- }
- else
- {
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
- arp_q = skb->next;
- }
skb->next = NULL;
skb->prev = NULL;
skb->arp = 1;
- sti();
skb->dev->queue_xmit (skb, skb->dev, 0);
-
- if (arp_q == NULL) break;
-
- cli();
}
- skb=skb2;
- } while (skb != arp_q);
- sti();
-
+ else
+ {
+ cli();
+ skb->magic = ARP_QUEUE_MAGIC;
+ if (arp_q == NULL)
+ {
+ skb->next = skb;
+ skb->prev = skb;
+ arp_q = skb;
+ }
+ else
+ {
+ skb->next = arp_q;
+ skb->prev = arp_q->prev;
+ arp_q->prev->next = skb;
+ arp_q->prev = skb;
+ }
+ sti();
+ }
+ }
}
static void
diff --git a/net/tcp/sock.c b/net/tcp/sock.c
index 3351e03..493cd9a 100644
--- a/net/tcp/sock.c
+++ b/net/tcp/sock.c
@@ -242,6 +242,12 @@ lock_skb (struct sk_buff *skb)
void
kfree_skb (struct sk_buff *skb, int rw)
{
+ if (skb == NULL)
+ {
+ printk ("kfree_skb: skb = NULL\n");
+ return;
+ }
+
if (skb->lock)
{
skb->free = 1;
@@ -300,7 +306,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
int best=0;
int size=32767; /* a big num. */
volatile struct sock *sk;
- start++;
+
if (base == 0) base = PROT_SOCK+1+(start % 1024);
if (base <= PROT_SOCK)
{
@@ -309,7 +315,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
/* now look through the entire array and try to find an empty
ptr. */
- for (i = 0; i < SOCK_ARRAY_SIZE; i++)
+ for (i=0; i < SOCK_ARRAY_SIZE; i++)
{
j = 0;
sk = prot->sock_array[(i+base+1) & (SOCK_ARRAY_SIZE -1)];
@@ -318,7 +324,13 @@ get_new_socknum(struct proto *prot, unsigned short base)
sk = sk->next;
j++;
}
- if (j == 0) return (i+base+1);
+ if (j == 0)
+ {
+ start = (i+1+start )%1024;
+ PRINTK ("get_new_socknum returning %d, start = %d\n",
+ i+base+1,start);
+ return (i+base+1);
+ }
if (j < size)
{
best = i;
@@ -330,6 +342,7 @@ get_new_socknum(struct proto *prot, unsigned short base)
{
best += SOCK_ARRAY_SIZE;
}
+ PRINTK ("get_new_socknum returning %d, start = %d\n", best+base+1,start);
return (best+base+1);
}
@@ -445,12 +458,15 @@ destroy_sock(volatile struct sock *sk)
/* just to be safe. */
sk->inuse = 1;
+ /* incase it's sleeping somewhere. */
+ if (!sk->dead) wake_up (sk->sleep);
+
remove_sock (sk);
/* now we can no longer get new packets. */
delete_timer((struct timer *)&sk->time_wait);
- if (sk->send_tmp) kfree_skb (sk->send_tmp, FREE_WRITE);
+ if (sk->send_tmp != NULL) kfree_skb (sk->send_tmp, FREE_WRITE);
/* cleanup up the write buffer. */
for (skb = sk->wfront; skb != NULL; )
@@ -617,7 +633,7 @@ destroy_sock(volatile struct sock *sk)
/* now if everything is gone we can free the socket structure,
otherwise we need to keep it around until everything is gone. */
- if (sk->rmem_alloc <= 0 && sk->wmem_alloc <= 0)
+ if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
{
kfree_s ((void *)sk,sizeof (*sk));
}
@@ -634,6 +650,8 @@ destroy_sock(volatile struct sock *sk)
sk->timeout = TIME_DESTROY;
reset_timer ((struct timer *)&sk->time_wait);
}
+
+ PRINTK ("leaving destroy_sock\n");
}
@@ -1004,10 +1022,9 @@ ip_proto_create (struct socket *sock, int protocol)
/* how many packets we should send before forcing an ack.
if this is set to zero it is the same as sk->delay_acks = 0 */
- sk->max_ack_backlog = MAX_ACK_BACKLOG;
+ sk->max_ack_backlog = 0;
sk->inuse = 0;
- sk->delay_acks = 1; /* default to waiting a while before sending
- acks. */
+ sk->delay_acks = 0;
sk->wback = NULL;
sk->wfront = NULL;
sk->rqueue = NULL;
@@ -1090,6 +1107,7 @@ ip_proto_release(struct socket *sock, struct socket *peer)
}
else
{
+ PRINTK ("sk->linger set.\n");
sk->prot->close(sk, 0);
cli();
while (sk->state != TCP_CLOSE)
@@ -1109,6 +1127,7 @@ ip_proto_release(struct socket *sock, struct socket *peer)
/* this will destroy it. */
release_sock (sk);
sock->data = NULL;
+ PRINTK ("ip_proto_release returning\n");
return (0);
}
diff --git a/net/tcp/tcp.c b/net/tcp/tcp.c
index 9d5d681..c944d0d 100644
--- a/net/tcp/tcp.c
+++ b/net/tcp/tcp.c
@@ -162,6 +162,8 @@ static void
tcp_time_wait (volatile struct sock *sk)
{
sk->state = TCP_TIME_WAIT;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead) wake_up (sk->sleep);
sk->time_wait.len = TCP_TIMEWAIT_LEN;
sk->timeout = TIME_CLOSE;
reset_timer ((struct timer *)&sk->time_wait);
@@ -219,11 +221,14 @@ tcp_err (int err, unsigned char *header, unsigned long daddr,
return;
}
+ printk ("tcp.c: icmp_err got error\n");
sk->err = icmp_err_convert[err & 0xff].errno;
if (icmp_err_convert[err & 0xff].fatal)
{
if (sk->state != TCP_ESTABLISHED)
- sk->state = TCP_CLOSE;
+ {
+ sk->state = TCP_CLOSE;
+ }
sk->prot->close(sk, 0);
}
@@ -232,61 +237,104 @@ tcp_err (int err, unsigned char *header, unsigned long daddr,
}
static int
+tcp_readable (volatile struct sock *sk)
+{
+ unsigned long counted;
+ unsigned long amount;
+ struct sk_buff *skb;
+ int count=0;
+ int sum;
+
+ if (sk == NULL || sk->rqueue == NULL) return (0);
+
+ counted = sk->copied_seq;
+ amount = 0;
+ skb = sk->rqueue->next;
+
+ /* go until a push or until we are out of data. */
+ do {
+ count ++;
+ if (count > 20)
+ {
+ printk ("tcp_readable, more than 20 packets without a psh\n");
+ printk ("possible read_queue corruption.\n");
+ return (amount);
+ }
+ if (before (counted+1, skb->h.th->seq)) break;
+ sum = skb->len - ( counted - skb->h.th->seq);
+ if (skb->h.th->syn) sum ++;
+ if (sum >= 0)
+ {
+ amount += sum;
+ if (skb->h.th->syn) amount --;
+ counted += sum;
+ if (skb->h.th->psh) break;
+ }
+ skb = skb->next;
+ } while (skb != sk->rqueue->next);
+ return (amount);
+}
+
+
+static int
tcp_select (volatile struct sock *sk, int sel_type, select_table *wait)
{
+ sk->inuse = 1;
switch (sel_type)
{
case SEL_IN:
select_wait (sk->sleep, wait);
- if (sk->rqueue != NULL &&
- (between (sk->copied_seq, sk->rqueue->next->h.th->seq - 1,
- sk->rqueue->next->h.th->seq + sk->rqueue->next->len) ||
- sk->state == TCP_LISTEN))
+ if (sk->rqueue != NULL)
{
- return (1);
+ if (sk->state == TCP_LISTEN || tcp_readable(sk))
+ {
+ release_sock (sk);
+ return (1);
+ }
}
- switch (sk->state)
- {
- case TCP_LISTEN:
- case TCP_ESTABLISHED:
- case TCP_FIN_WAIT1:
- case TCP_SYN_SENT:
- case TCP_SYN_RECV:
- case TCP_FIN_WAIT2:
- return (0);
- default:
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ release_sock (sk);
return (1);
+ }
+ else
+ {
+ release_sock (sk);
+ return (0);
}
case SEL_OUT:
select_wait (sk->sleep, wait);
- switch(sk->state)
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ release_sock (sk);
+ return (0);
+ }
+ /* hack so it will probably be able to write something
+ if it says it's ok to write. */
+ if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
- default:
+ release_sock (sk);
return (1);
+ }
+ release_sock (sk);
+ return (0);
- case TCP_SYN_SENT:
- case TCP_SYN_RECV:
- return (0);
- case TCP_ESTABLISHED:
- case TCP_CLOSE_WAIT:
- /* hack so it will probably be able to write something
- if it says it's ok to write. */
- if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) return (1);
- return (0);
+ case SEL_EX:
+ select_wait(sk->sleep,wait);
+ if (sk->err)
+ {
+ release_sock (sk);
+ return (1);
}
+ release_sock (sk);
+ return (0);
+ }
- case SEL_EX:
- select_wait(sk->sleep,wait);
- if (sk->err) return (1);
- if (sk->state == TCP_TIME_WAIT ||
- sk->state == TCP_LAST_ACK)
- return (1);
- return (0);
- }
+ release_sock (sk);
return (0);
}
@@ -303,32 +351,17 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
/* case FIONREAD:*/
{
unsigned long amount;
- unsigned long counted;
- int sum;
- struct sk_buff *skb;
if (sk->state == TCP_LISTEN)
return (-EINVAL);
- counted = sk->copied_seq;
amount = 0;
+ sk->inuse = 1;
if (sk->rqueue != NULL)
{
- skb = sk->rqueue->next;
- /* go until a push or until we are out of data. */
- do {
- if (before (counted+1, skb->h.th->seq)) break;
- sum = skb->len + skb->h.th->seq - counted;
- if (sum > 0)
- {
- amount += sum;
- counted += sum;
- }
- if (skb->h.th->psh) break;
- skb = skb->next;
-
- } while (skb != sk->rqueue->next);
+ amount = tcp_readable(sk);
}
+ release_sock (sk);
PRINTK ("returning %d\n", amount);
verify_area ((void *)arg, sizeof (unsigned long));
put_fs_long (amount, (unsigned long *)arg);
@@ -340,12 +373,14 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
struct sk_buff *skb;
int answ=0;
/* try to figure out if we need to read some urgent data. */
+ sk->inuse = 1;
if (sk->rqueue != NULL)
{
skb = sk->rqueue->next;
if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
answ = 1;
}
+ release_sock (sk);
verify_area ((void *) arg, sizeof (unsigned long));
put_fs_long (answ, (void *) arg);
return (0);
@@ -641,8 +676,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
if (nonblock)
{
- PRINTK ("tcp_write: return 2\n");
release_sock (sk);
+ PRINTK ("tcp_write: return 2\n");
if (copied) return (copied);
return (-EAGAIN);
}
@@ -655,7 +690,8 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
go to sleep. */
release_sock (sk);
cli();
- if (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
+ if (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
+ sk->err == 0)
{
interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked)
@@ -752,7 +788,9 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
/* again we will try to avoid it. */
cli ();
- if (tmp <= sk->wmem_alloc)
+ if (tmp <= sk->wmem_alloc
+ && (sk->state == TCP_ESTABLISHED || sk->state == TCP_CLOSE_WAIT )
+ && sk->err == 0)
{
interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked)
@@ -971,18 +1009,26 @@ cleanup_rbuf (volatile struct sock *sk)
/* at this point we should send an ack if the difference in
the window, and the amount of space is bigger than
TCP_WINDOW_DIFF */
-/* PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n",
- sk->window - sk->bytes_rcv, sk->prot->rspace(sk));*/
+ PRINTK ("sk->window left = %d, sk->prot->rspace(sk)=%d\n",
+ sk->window - sk->bytes_rcv, sk->prot->rspace(sk));
if ((sk->prot->rspace(sk) >
(sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF)))
{
sk->ack_backlog++;
- /* force it to send an ack soon. */
- if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when))
+ if (sk->ack_backlog > sk->max_ack_backlog)
{
- sk->time_wait.len = TCP_ACK_TIME;
- reset_timer ((struct timer *)&sk->time_wait);
+ tcp_read_wakeup (sk);
+ }
+ else
+ {
+ /* force it to send an ack soon. */
+ if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when))
+ {
+ sk->time_wait.len = TCP_ACK_TIME;
+ sk->timeout = TIME_WRITE;
+ reset_timer ((struct timer *)&sk->time_wait);
+ }
}
}
@@ -1043,7 +1089,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
/* now at this point, we may have gotten some data. */
release_sock (sk);
cli();
- if (sk->urg == 0 || sk->rqueue == NULL)
+ if ((sk->urg == 0 || sk->rqueue == NULL) && sk->err == 0
+ && !(sk->shutdown & RCV_SHUTDOWN) )
{
interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked)
@@ -1085,8 +1132,8 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
/* This routine copies from a sock struct into the user buffer. */
static int
-tcp_read(volatile struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags)
+tcp_read (volatile struct sock *sk, unsigned char *to,
+ int len, int nonblock, unsigned flags)
{
int copied=0; /* will be used to say how much has been copied. */
struct sk_buff *skb;
@@ -1102,15 +1149,6 @@ tcp_read(volatile struct sock *sk, unsigned char *to,
/* this error should be checked. */
if (sk->state == TCP_LISTEN) return (-ENOTCONN);
- /* will catch some errors. */
- if (sk->err)
- {
- int err;
- err = -sk->err;
- sk->err = 0;
- return (err);
- }
-
/* urgent data needs to be handled specially. */
if ((flags & MSG_OOB))
return (tcp_read_urg (sk, nonblock, to, len, flags));
@@ -1184,10 +1222,17 @@ tcp_read(volatile struct sock *sk, unsigned char *to,
PRINTK ("tcp_read about to sleep. state = %d\n",sk->state);
release_sock (sk); /* now we may have some data waiting. */
+ /* or we could have changed state. */
cli();
+ if ( sk->shutdown & RCV_SHUTDOWN || sk->err != 0)
+ {
+ sk->inuse = 1;
+ sti();
+ continue;
+ }
if ( sk->rqueue == NULL ||
- before (sk->copied_seq+1, sk->rqueue->next->h.th->seq))
+ before (sk->copied_seq+1, sk->rqueue->next->h.th->seq) )
{
interruptible_sleep_on (sk->sleep);
if (current->signal & ~current->blocked)
@@ -1299,6 +1344,7 @@ tcp_shutdown (volatile struct sock *sk, int how)
*/
if (!(how & SEND_SHUTDOWN)) return;
+ sk->inuse = 1;
/* clear out any half completed packets. */
if (sk->send_tmp)
@@ -1306,11 +1352,15 @@ tcp_shutdown (volatile struct sock *sk, int how)
prot = (struct proto *)sk->prot;
th=(struct tcp_header *)&sk->dummy_th;
- buff=prot->wmalloc(sk, MAX_RESET_SIZE,1, GFP_KERNEL);
- if (buff == NULL) return;
-
+ release_sock (sk); /* incase the malloc sleeps. */
+ buff=prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
+ if (buff == NULL)
+ {
+ return;
+ }
sk->inuse = 1;
+
PRINTK("tcp_shutdown_send buff = %X\n", buff);
buff->mem_addr = buff;
buff->mem_len = MAX_RESET_SIZE;
@@ -1326,8 +1376,8 @@ tcp_shutdown (volatile struct sock *sk, int how)
if (tmp < 0)
{
prot->wfree (sk,buff->mem_addr, buff->mem_len);
- PRINTK ("Unable to build header for fin.\n");
release_sock(sk);
+ PRINTK ("Unable to build header for fin.\n");
return;
}
@@ -1338,7 +1388,6 @@ tcp_shutdown (volatile struct sock *sk, int how)
memcpy (t1, th, sizeof (*t1));
t1->seq = net32(sk->send_seq);
- sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->send_seq++;
buff->h.seq = sk->send_seq;
@@ -1683,8 +1732,9 @@ tcp_close (volatile struct sock *sk, int timeout)
struct device *dev=NULL;
int tmp;
PRINTK ("tcp_close ((struct sock *)%X, %d)\n",sk, timeout);
+ print_sk (sk);
sk->inuse = 1;
- sk->keepopen = 0;
+ sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
@@ -1700,10 +1750,13 @@ tcp_close (volatile struct sock *sk, int timeout)
skb = sk->rqueue;
do {
skb2=skb->next;
+ /* if there is some real unread data, send a reset. */
+ if (skb->len > 0 &&
+ after (skb->h.th->seq + skb->len + 1, sk->copied_seq))
+ need_reset = 1;
kfree_skb (skb, FREE_READ);
skb=skb2;
} while (skb != sk->rqueue);
- need_reset = 1;
}
sk->rqueue = NULL;
@@ -1726,8 +1779,6 @@ tcp_close (volatile struct sock *sk, int timeout)
if (timeout)
tcp_time_wait(sk);
release_sock (sk);
- if (!need_reset)
- return;
break;
case TCP_TIME_WAIT:
@@ -2117,14 +2168,18 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
/* see if we are done. */
if ( sk->state == TCP_TIME_WAIT)
{
- if (sk->rcv_ack_seq == sk->send_seq &&
- sk->acked_seq == sk->fin_seq);
if (!sk->dead) wake_up (sk->sleep);
- sk->state = TCP_CLOSE;
+ if (sk->rcv_ack_seq == sk->send_seq &&
+ sk->acked_seq == sk->fin_seq)
+ {
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ }
}
if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2)
{
+ if (!sk->dead) wake_up (sk->sleep);
if (sk->rcv_ack_seq == sk->send_seq)
{
if (sk->acked_seq != sk->fin_seq)
@@ -2133,11 +2188,13 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
}
else
{
+ PRINTK ("tcp_ack closing socket - %X\n", sk);
+ print_sk (sk);
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, sk->daddr);
- sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->state = TCP_CLOSE;
}
}
- if (!sk->dead) wake_up (sk->sleep);
}
PRINTK ("leaving tcp_ack\n");
@@ -2176,17 +2233,16 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (sk->shutdown & RCV_SHUTDOWN)
{
- /* just ack everything. */
sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
- tcp_send_ack (sk->send_seq, sk->acked_seq, sk, skb->h.th, saddr);
+ tcp_reset (sk->saddr, sk->daddr, skb->h.th,
+ sk->prot, NULL, skb->dev);
+ sk->state = TCP_CLOSE;
+ sk->err = EPIPE;
+ sk->shutdown = SHUTDOWN_MASK;
+ PRINTK ("tcp_data: closing socket - %X\n", sk);
+ print_sk (sk);
kfree_skb (skb, FREE_READ);
- if (sk->acked_seq == sk->fin_seq)
- {
- if (!sk->dead) wake_up (sk->sleep);
- if (sk->state == TCP_TIME_WAIT || sk->state == TCP_LAST_ACK
- || sk->state == TCP_FIN_WAIT2)
- sk->state = TCP_CLOSE;
- }
+ if (!sk->dead) wake_up (sk->sleep);
return (0);
}
@@ -2250,7 +2306,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (before (sk->acked_seq, sk->copied_seq))
{
- PRINTK ("*** tcp.c:tcp_data bug acked < copied\n");
+ printk ("*** tcp.c:tcp_data bug acked < copied\n");
sk->acked_seq = sk->copied_seq;
}
@@ -2266,6 +2322,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
/* when we ack the fin, we turn on the RCV_SHUTDOWN flag. */
if (skb->h.th->fin)
{
+ if (!sk->dead) wake_up (sk->sleep);
sk->shutdown |= RCV_SHUTDOWN;
}
@@ -2281,6 +2338,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
if (skb2->h.th->fin)
{
sk->shutdown |= RCV_SHUTDOWN;
+ if (!sk->dead) wake_up (sk->sleep);
}
/* force an immediate ack. */
@@ -2308,6 +2366,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
sk->time_wait.len = TCP_ACK_TIME;
sk->timeout = TIME_WRITE;
reset_timer ((struct timer *)&sk->time_wait);
+ sk->retransmits = 0;
}
}
}
@@ -2327,10 +2386,15 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
PRINTK ("data received on dead socket. \n");
}
- if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq)
+ if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq
+ && sk->rcv_ack_seq == sk->send_seq)
{
+ PRINTK ("tcp_data: entering last_ack state sk = %X\n", sk);
+ print_sk (sk);
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, saddr);
+ sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_LAST_ACK;
+ if (!sk->dead) wake_up (sk->sleep);
}
return (0);
@@ -2384,19 +2448,21 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
wake_up (sk->sleep);
}
- sk->err = 0;
switch (sk->state)
{
case TCP_SYN_RECV:
case TCP_SYN_SENT:
case TCP_ESTABLISHED:
+ sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_CLOSE_WAIT;
break;
case TCP_CLOSE_WAIT:
+ case TCP_FIN_WAIT2:
break; /* we got a retransmit of the fin. */
case TCP_FIN_WAIT1:
+ sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_FIN_WAIT2;
break;
@@ -2409,9 +2475,6 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
reset_timer ((struct timer *)&sk->time_wait);
return (0);
- case TCP_FIN_WAIT2:
- sk->state = TCP_CLOSE;
- return (0);
}
/* there is no longer any reason to do this. Just let tcp_data
deal with it. */
@@ -2563,12 +2626,13 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
memcpy_fromfs (&sin,usin, min(sizeof (sin), addr_len));
if (sin.sin_family && sin.sin_family != AF_INET) return (-EAFNOSUPPORT);
-
+ sk->inuse = 1;
sk->daddr = sin.sin_addr.s_addr;
sk->send_seq = timer_seq*SEQ_TICK-seq_offset;
sk->rcv_ack_seq = sk->send_seq -1;
sk->err = 0;
sk->dummy_th.dest = sin.sin_port;
+ release_sock (sk);
buff=sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
if (buff == NULL)
@@ -2626,7 +2690,7 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
sk->time_wait.len = TCP_CONNECT_TIME;
reset_timer ((struct timer *)&sk->time_wait);
- sk->retransmits = TCP_RETR1 - TCP_SYN_RETRIES;
+ sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
release_sock (sk);
return (0);
}
@@ -2835,6 +2899,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
{
wake_up (sk->sleep);
@@ -2859,20 +2924,34 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
if (th->rst)
{
+ /* this means the thing should really be closed. */
sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- if (!sk->dead)
+
+ if (sk->state == TCP_CLOSE_WAIT)
{
- wake_up (sk->sleep);
+ sk->err = EPIPE;
+ }
+
+ /* a reset with a fin just means that the
+ data was not all read. */
+ if (!th->fin)
+ {
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ {
+ wake_up (sk->sleep);
+ }
+ kfree_skb (skb, FREE_READ);
+ release_sock(sk);
+ return (0);
}
- kfree_skb (skb, FREE_READ);
- release_sock(sk);
- return (0);
}
if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
+ sk->state = SHUTDOWN_MASK;
tcp_reset (daddr, saddr, th, sk->prot, opt,dev);
if (!sk->dead)
{
@@ -2902,6 +2981,13 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
}
}
+ if (th->fin && tcp_fin (sk, th, saddr, dev))
+ {
+ kfree_skb (skb, FREE_READ);
+ release_sock(sk);
+ return (0);
+ }
+
if ( tcp_data (skb, sk, saddr, len))
{
kfree_skb (skb, FREE_READ);
@@ -2909,13 +2995,6 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return (0);
}
- if (!th->fin)
- {
- release_sock(sk);
- return (0);
- }
-
- tcp_fin (sk, th, saddr, dev);
release_sock(sk);
return (0);
@@ -2989,8 +3068,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
case TCP_SYN_SENT:
if (th->rst)
{
- sk->err = ECONNREFUSED;
+ sk->err = ECONNREFUSED ;
sk->state = TCP_CLOSE;
+ sk->state = SHUTDOWN_MASK;
if (!sk->dead)
{
wake_up (sk->sleep);
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 8401aea..f428073 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -84,23 +84,23 @@ enum {
#define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER
#define MAX_WINDOW 12000
#define MIN_WINDOW 2048
-#define MAX_ACK_BACKLOG 8
+#define MAX_ACK_BACKLOG 2
#define MIN_WRITE_SPACE 2048
#define TCP_WINDOW_DIFF 2048
-#define TCP_RETR1 7 /* this is howmany retries it does
+#define TCP_RETR1 10 /* this is howmany retries it does
before it tries to figure out
if the gateway is down. */
-#define TCP_RETR2 10 /* this should take between 3 and
- ten minutes ( 1024 * rtt). */
+#define TCP_RETR2 25 /* this should take at least
+ 90 minutes to time out. */
#define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs. */
#define TCP_TIMEWAIT_LEN 6000 /* How long to wait to sucessfully
close the socket, about 60 seconds. */
#define TCP_ACK_TIME 35 /* time to delay before sending an ack. */
-#define TCP_DONE_TIME 2500 /* maximum time to wait before actually destroying
+#define TCP_DONE_TIME 250 /* maximum time to wait before actually destroying
a socket. */
#define TCP_WRITE_TIME 100 /* initial time to wait for an ack,
after last transmit. */
diff --git a/net/tcp/timer.c b/net/tcp/timer.c
index 37a829f..080e9dc 100644
--- a/net/tcp/timer.c
+++ b/net/tcp/timer.c
@@ -232,8 +232,18 @@ net_timer (void)
break;
case TIME_WRITE: /* try to retransmit. */
+ /* it could be we got here because we needed
+ to send an ack. So we need to check for that. */
if (sk->send_head != NULL)
{
+ if (before (jiffies, sk->send_head->when + 2*sk->rtt))
+ {
+ sk->time_wait.len = 2*sk->rtt;
+ sk->timeout = TIME_WRITE;
+ reset_timer ((struct timer *)&sk->time_wait);
+ release_sock (sk);
+ break;
+ }
PRINTK ("retransmitting.\n");
sk->prot->retransmit (sk, 0);
@@ -268,27 +278,6 @@ net_timer (void)
release_sock (sk);
break;
}
-
- /* if we have stuff which hasn't been written because the
- window is too small, fall throught to TIME_KEEPOPEN */
- if (sk->wfront == NULL && sk->send_tmp == NULL)
- {
- release_sock (sk);
- break;
- }
-
- /* this basically assumes tcp here. */
- /* exponential fall back. */
- /* The rtt should quickly get back to normal once
- we start sending packets again. */
-
- sk->rtt *= 2;
- sk->time_wait.len = sk->rtt;
- sk->timeout = TIME_WRITE;
- if (sk->prot->write_wakeup != NULL)
- sk->prot->write_wakeup(sk);
-
- reset_timer ((struct timer *)&sk->time_wait);
release_sock (sk);
break;
@@ -298,6 +287,12 @@ net_timer (void)
if (sk->prot->write_wakeup != NULL)
sk->prot->write_wakeup(sk);
sk->retransmits ++;
+ if (sk->shutdown == SHUTDOWN_MASK)
+ {
+ sk->prot->close (sk,1);
+ sk->state = TCP_CLOSE;
+ }
+
if (sk->retransmits > TCP_RETR1)
{
PRINTK ("timer.c TIME_KEEPOPEN time-out 1\n");
diff --git a/net/unix.c b/net/unix.c
index 1257542..ec2c4d5 100644
--- a/net/unix.c
+++ b/net/unix.c
@@ -184,6 +184,26 @@ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
return (unix_proto_read (sock, buff, len, nonblock));
}
+/*
+ * Since unix domain sockets use filenames to communicate, two sockets are
+ * the same if their strings are the same, even if their lengths are different
+ * (due to possible null terminations). Verified under SunOS 4.1.2
+ */
+static int
+same_path(char *s1, int l1, char *s2, int l2)
+{
+ /*
+ * Skip chars while they're equal
+ */
+ for (; l1 && l2 && *s1 == *s2; ++s1, ++s2, --l1, --l2);
+
+ /*
+ * Both must be exhausted, or one must be null terminated and the
+ * other either exhausted or null terminated, for the paths to be
+ * equivalent
+ */
+ return ((l1 == 0 || *s1 == '\0') && (l2 == 0 || *s2 == '\0'));
+}
static struct unix_proto_data *
unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
@@ -193,8 +213,10 @@ unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len)
for (upd = unix_datas; upd <= last_unix_data; ++upd) {
if (upd->refcnt && upd->socket &&
upd->socket->state == SS_UNCONNECTED &&
- upd->sockaddr_len == sockaddr_len &&
- memcmp(&upd->sockaddr_un, sockun, sockaddr_len) == 0)
+ upd->sockaddr_un.sun_family == sockun->sun_family &&
+ same_path(sockun->sun_path, sockaddr_len - UN_PATH_OFFSET,
+ upd->sockaddr_un.sun_path,
+ upd->sockaddr_len - UN_PATH_OFFSET))
return upd;
}
return NULL;
diff --git a/tools/version.h b/tools/version.h
index 15e45b1..dd045d4 100644
--- a/tools/version.h
+++ b/tools/version.h
@@ -1,5 +1,5 @@
-#define UTS_RELEASE "0.99-44"
-#define UTS_VERSION "12/11/92"
-#define LINUX_COMPILE_TIME "23:05:18"
+#define UTS_RELEASE "0.99.pl1-46"
+#define UTS_VERSION "12/20/92"
+#define LINUX_COMPILE_TIME "14:31:20"
#define LINUX_COMPILE_BY "root"
#define LINUX_COMPILE_HOST "home"