aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-01-26 12:08:25 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:29 -0400
commitcdf6bc43e624291b32c55a499e40625aff5de89b (patch)
tree42ec33965866208fdfa03de1aaa1cb53aee4b90f
parent95c5f0cce26ec795afe80ee9fb9a48f22aba2ae2 (diff)
downloadarchive-cdf6bc43e624291b32c55a499e40625aff5de89b.tar.gz
ALPHA-pl14v
-rw-r--r--Makefile2
-rw-r--r--drivers/FPU-emu/errors.c14
-rw-r--r--drivers/FPU-emu/fpu_emu.h6
-rw-r--r--drivers/FPU-emu/fpu_entry.c7
-rw-r--r--drivers/FPU-emu/fpu_system.h20
-rw-r--r--drivers/FPU-emu/get_address.c32
-rw-r--r--drivers/FPU-emu/load_store.c7
-rw-r--r--drivers/FPU-emu/poly_sin.c10
-rw-r--r--drivers/FPU-emu/reg_ld_str.c127
-rw-r--r--drivers/FPU-emu/version.h2
-rw-r--r--drivers/char/atixlmouse.c1
-rw-r--r--drivers/char/busmouse.c1
-rw-r--r--drivers/char/console.c3
-rw-r--r--drivers/char/keyboard.c39
-rw-r--r--drivers/char/msbusmouse.c1
-rw-r--r--drivers/char/pty.c54
-rw-r--r--drivers/char/serial.c16
-rw-r--r--drivers/char/tty_io.c905
-rw-r--r--drivers/char/tty_ioctl.c459
-rw-r--r--drivers/net/8390.c1
-rw-r--r--drivers/net/lance.c9
-rw-r--r--drivers/net/slip.c2
-rw-r--r--fs/open.c4
-rw-r--r--include/linux/kernel.h5
-rw-r--r--include/linux/mm.h19
-rw-r--r--include/linux/sched.h30
-rw-r--r--include/linux/termios.h1
-rw-r--r--include/linux/tty.h126
-rw-r--r--kernel/fork.c3
-rw-r--r--kernel/ksyms.S2
-rw-r--r--kernel/sys.c3
-rw-r--r--mm/memory.c11
-rw-r--r--net/inet/ip.c3
-rw-r--r--net/inet/skbuff.c35
-rw-r--r--net/inet/skbuff.h4
-rw-r--r--net/inet/tcp.c141
-rw-r--r--net/socket.c1
37 files changed, 1167 insertions, 939 deletions
diff --git a/Makefile b/Makefile
index f0a7744..504d696 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = u
+ALPHA = v
all: Version zImage
diff --git a/drivers/FPU-emu/errors.c b/drivers/FPU-emu/errors.c
index 8506997..309ba60 100644
--- a/drivers/FPU-emu/errors.c
+++ b/drivers/FPU-emu/errors.c
@@ -38,7 +38,8 @@ void Un_impl(void)
{
unsigned char byte1, FPU_modrm;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ /* No need to verify_area(), we have previously fetched these bytes. */
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
@@ -49,7 +50,7 @@ void Un_impl(void)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
else
printk("/%d\n", (FPU_modrm >> 3) & 7);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
EXCEPTION(EX_Invalid);
@@ -65,7 +66,8 @@ void emu_printall()
"DeNorm", "Inf", "NaN", "Empty" };
unsigned char byte1, FPU_modrm;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ /* No need to verify_area(), we have previously fetched these bytes. */
byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
partial_status = status_word();
@@ -154,7 +156,7 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
(long)(FPU_loaded_data.sigl & 0xFFFF),
FPU_loaded_data.exp - EXP_BIAS + 1);
printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
}
@@ -261,7 +263,7 @@ void exception(int n)
}
}
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
{
#ifdef PRINT_MESSAGES
@@ -303,7 +305,7 @@ void exception(int n)
*/
/* regs[0].tag |= TW_FPU_Interrupt; */
}
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
#ifdef __DEBUG__
math_abort(FPU_info,SIGFPE);
diff --git a/drivers/FPU-emu/fpu_emu.h b/drivers/FPU-emu/fpu_emu.h
index 6d7c2db..597189a 100644
--- a/drivers/FPU-emu/fpu_emu.h
+++ b/drivers/FPU-emu/fpu_emu.h
@@ -1,7 +1,7 @@
/*---------------------------------------------------------------------------+
| fpu_emu.h |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -62,8 +62,8 @@
#ifdef PARANOID
extern char emulating;
-# define RE_ENTRANT_CHECK_OFF emulating = 0;
-# define RE_ENTRANT_CHECK_ON emulating = 1;
+# define RE_ENTRANT_CHECK_OFF emulating = 0
+# define RE_ENTRANT_CHECK_ON emulating = 1
#else
# define RE_ENTRANT_CHECK_OFF
# define RE_ENTRANT_CHECK_ON
diff --git a/drivers/FPU-emu/fpu_entry.c b/drivers/FPU-emu/fpu_entry.c
index 0498a1a..527cb36 100644
--- a/drivers/FPU-emu/fpu_entry.c
+++ b/drivers/FPU-emu/fpu_entry.c
@@ -209,6 +209,7 @@ asmlinkage void math_emulate(long arg)
do_another_FPU_instruction:
RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
@@ -301,6 +302,7 @@ do_another_FPU_instruction:
{
FPU_EIP++;
RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
code = get_fs_word((unsigned short *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
}
@@ -560,6 +562,7 @@ FPU_fwait_done:
unsigned char next;
RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
next = get_fs_byte((unsigned char *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
if ( valid_prefix(next) )
@@ -591,8 +594,10 @@ static int valid_prefix(unsigned char byte)
case PREFIX_GS:
case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */
+ FPU_EIP++;
RE_ENTRANT_CHECK_OFF;
- byte = get_fs_byte((unsigned char *) (++FPU_EIP));
+ FPU_code_verify_area(1);
+ byte = get_fs_byte((unsigned char *) (FPU_EIP));
RE_ENTRANT_CHECK_ON;
break;
case FWAIT_OPCODE:
diff --git a/drivers/FPU-emu/fpu_system.h b/drivers/FPU-emu/fpu_system.h
index e8e50c5..52ae0f7 100644
--- a/drivers/FPU-emu/fpu_system.h
+++ b/drivers/FPU-emu/fpu_system.h
@@ -1,7 +1,8 @@
/*---------------------------------------------------------------------------+
| fpu_system.h |
| |
- | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Copyright (C) 1992,1994 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
@@ -41,6 +42,23 @@
#define data_operand_offset (I387.soft.foo)
#define operand_selector (I387.soft.fos)
+#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \
+ math_abort(FPU_info,SIGSEGV)
+
+#undef FPU_IGNORE_CODE_SEGV
+#ifdef FPU_IGNORE_CODE_SEGV
+/* verify_area() is very expensive, and causes the emulator to run
+ about 20% slower if applied to the code. Anyway, errors due to bad
+ code addresses should be much rarer than errors due to bad data
+ addresses. */
+#define FPU_code_verify_area(z)
+#else
+/* A simpler test than verify_area() can probably be done for
+ FPU_code_verify_area() because the only possible error is to step
+ past the upper boundary of a legal code area. */
+#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z)
+#endif
+
/* ######## temporary and ugly ;-) */
#define FPU_data_address ((void *)(I387.soft.twd))
diff --git a/drivers/FPU-emu/get_address.c b/drivers/FPU-emu/get_address.c
index 98f97d6..7742661 100644
--- a/drivers/FPU-emu/get_address.c
+++ b/drivers/FPU-emu/get_address.c
@@ -3,7 +3,7 @@
| |
| Get the effective address from an FPU instruction. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -46,9 +46,10 @@ static void *sib(int mod)
unsigned char ss,index,base;
long offset;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_EIP++;
ss = base >> 6;
index = (base >> 3) & 7;
@@ -74,17 +75,19 @@ static void *sib(int mod)
if (mod == 1)
{
/* 8 bit signed displacement */
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
offset += (signed char) get_fs_byte((char *) FPU_EIP);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_EIP++;
}
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
{
/* 32 bit displacment */
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(4);
offset += (signed) get_fs_long((unsigned long *) FPU_EIP);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_EIP += 4;
}
@@ -135,9 +138,10 @@ void get_address(unsigned char FPU_modrm)
if (FPU_rm == 5)
{
/* Special case: disp32 */
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(4);
offset = get_fs_long((unsigned long *) FPU_EIP);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_EIP += 4;
FPU_data_address = (void *) offset;
return;
@@ -150,16 +154,18 @@ void get_address(unsigned char FPU_modrm)
}
case 1:
/* 8 bit signed displacement */
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(1);
offset = (signed char) get_fs_byte((char *) FPU_EIP);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_EIP++;
break;
case 2:
/* 32 bit displacement */
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_code_verify_area(4);
offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_EIP += 4;
break;
case 3:
diff --git a/drivers/FPU-emu/load_store.c b/drivers/FPU-emu/load_store.c
index 2966b07..f7b6c9c 100644
--- a/drivers/FPU-emu/load_store.c
+++ b/drivers/FPU-emu/load_store.c
@@ -4,7 +4,7 @@
| This file contains most of the code to interpret the FPU instructions |
| which load and store from user memory. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -168,6 +168,7 @@ switch ( type )
break;
case 024: /* fldcw */
RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, FPU_data_address, 2);
control_word = get_fs_word((unsigned short *) FPU_data_address);
RE_ENTRANT_CHECK_ON;
if ( partial_status & ~control_word & CW_Exceptions )
@@ -206,7 +207,7 @@ switch ( type )
break;
case 034: /* fstcw m16int */
RE_ENTRANT_CHECK_OFF;
- verify_area(VERIFY_WRITE,FPU_data_address,2);
+ FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
put_fs_word(control_word, (short *) FPU_data_address);
RE_ENTRANT_CHECK_ON;
NO_NET_DATA_EFFECT;
@@ -220,7 +221,7 @@ switch ( type )
break;
case 036: /* fstsw m2byte */
RE_ENTRANT_CHECK_OFF;
- verify_area(VERIFY_WRITE,FPU_data_address,2);
+ FPU_verify_area(VERIFY_WRITE,FPU_data_address,2);
put_fs_word(status_word(),(short *) FPU_data_address);
RE_ENTRANT_CHECK_ON;
NO_NET_DATA_EFFECT;
diff --git a/drivers/FPU-emu/poly_sin.c b/drivers/FPU-emu/poly_sin.c
index b6a0507..aa43448 100644
--- a/drivers/FPU-emu/poly_sin.c
+++ b/drivers/FPU-emu/poly_sin.c
@@ -3,7 +3,7 @@
| |
| Computation of an approximation of the sin function by a polynomial |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -128,20 +128,20 @@ void poly_sine(FPU_REG const *arg, FPU_REG *result)
)
{
#ifdef DEBUGGING
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
result->sigh, result->sigl);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
#endif DEBUGGING
EXCEPTION(EX_INTERNAL|0x103);
}
#ifdef DEBUGGING
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
result->sigh, result->sigl);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
#endif DEBUGGING
result->sigl = 0; /* Truncate the result to 1.00 */
diff --git a/drivers/FPU-emu/reg_ld_str.c b/drivers/FPU-emu/reg_ld_str.c
index c9d7495..7210a0a 100644
--- a/drivers/FPU-emu/reg_ld_str.c
+++ b/drivers/FPU-emu/reg_ld_str.c
@@ -3,7 +3,7 @@
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -49,13 +49,14 @@ int reg_load_extended(void)
long double *s = (long double *)FPU_data_address;
unsigned long sigl, sigh, exp;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 10);
/* Use temporary variables here because FPU_loaded data is
static and hence re-entrancy problems can arise */
sigl = get_fs_long((unsigned long *) s);
sigh = get_fs_long(1 + (unsigned long *) s);
exp = get_fs_word(4 + (unsigned short *) s);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
FPU_loaded_data.tag = TW_Valid; /* Default */
FPU_loaded_data.sigl = sigl;
@@ -150,10 +151,11 @@ int reg_load_double(void)
int exp;
unsigned m64, l64;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, dfloat, 8);
m64 = get_fs_long(1 + (unsigned long *) dfloat);
l64 = get_fs_long((unsigned long *) dfloat);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
if (m64 & 0x80000000)
FPU_loaded_data.sign = SIGN_NEG;
@@ -227,9 +229,10 @@ int reg_load_single(void)
unsigned m32;
int exp;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, single, 4);
m32 = get_fs_long((unsigned long *) single);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
if (m32 & 0x80000000)
FPU_loaded_data.sign = SIGN_NEG;
@@ -295,10 +298,11 @@ void reg_load_int64(void)
int e;
long long s;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, _s, 8);
((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s);
((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
if (s == 0)
{ reg_move(&CONST_Z, &FPU_loaded_data); return; }
@@ -326,9 +330,10 @@ void reg_load_int32(void)
long s;
int e;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, _s, 4);
s = (long)get_fs_long((unsigned long *) _s);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
if (s == 0)
{ reg_move(&CONST_Z, &FPU_loaded_data); return; }
@@ -356,10 +361,11 @@ void reg_load_int16(void)
short *_s = (short *)FPU_data_address;
int s, e;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, _s, 2);
/* Cast as short to get the sign extended. */
s = (short)get_fs_word((unsigned short *) _s);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
if (s == 0)
{ reg_move(&CONST_Z, &FPU_loaded_data); return; }
@@ -390,12 +396,15 @@ void reg_load_bcd(void)
unsigned char bcd;
long long l=0;
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 10);
+ RE_ENTRANT_CHECK_ON;
for ( pos = 8; pos >= 0; pos--)
{
l *= 10;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
l += bcd >> 4;
l *= 10;
l += bcd & 0x0f;
@@ -403,11 +412,11 @@ void reg_load_bcd(void)
/* Finish all access to user memory before putting stuff into
the static FPU_loaded_data */
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
FPU_loaded_data.sign =
((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
SIGN_NEG : SIGN_POS;
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
if (l == 0)
{
@@ -438,7 +447,9 @@ int reg_store_extended(void)
if ( FPU_st0_tag != TW_Empty )
{
- verify_area(VERIFY_WRITE, d, 10);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE, d, 10);
+ RE_ENTRANT_CHECK_ON;
write_to_extended(FPU_st0_ptr, (char *) FPU_data_address);
return 1;
}
@@ -450,7 +461,7 @@ int reg_store_extended(void)
/* The masked response */
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
- verify_area(VERIFY_WRITE,d,10);
+ FPU_verify_area(VERIFY_WRITE,d,10);
put_fs_long(0, (unsigned long *) d);
put_fs_long(0xc0000000, 1 + (unsigned long *) d);
put_fs_word(0xffff, 4 + (short *) d);
@@ -635,11 +646,11 @@ int reg_store_double(void)
{
/* The masked response */
/* Put out the QNaN indefinite */
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,(void *)dfloat,8);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
put_fs_long(0, (unsigned long *) dfloat);
put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
else
@@ -648,11 +659,11 @@ int reg_store_double(void)
if (FPU_st0_ptr->sign)
l[1] |= 0x80000000;
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,(void *)dfloat,8);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
put_fs_long(l[0], (unsigned long *)dfloat);
put_fs_long(l[1], 1 + (unsigned long *)dfloat);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -819,10 +830,10 @@ int reg_store_single(void)
{
/* The masked response */
/* Put out the QNaN indefinite */
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,(void *)single,4);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)single,4);
put_fs_long(0xffc00000, (unsigned long *) single);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
else
@@ -838,10 +849,10 @@ int reg_store_single(void)
if (FPU_st0_ptr->sign)
templ |= 0x80000000;
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,(void *)single,4);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)single,4);
put_fs_long(templ,(unsigned long *) single);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -896,11 +907,11 @@ int reg_store_int64(void)
tll = - tll;
}
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,(void *)d,8);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,(void *)d,8);
put_fs_long(((long *)&tll)[0],(unsigned long *) d);
put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -951,10 +962,10 @@ int reg_store_int32(void)
t.sigl = -(long)t.sigl;
}
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,d,4);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,4);
put_fs_long(t.sigl, (unsigned long *) d);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -1005,10 +1016,10 @@ int reg_store_int16(void)
t.sigl = -t.sigl;
}
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,d,2);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,2);
put_fs_word((short)t.sigl,(short *) d);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -1045,14 +1056,14 @@ int reg_store_bcd(void)
if ( control_word & CW_Invalid )
{
/* Produce the QNaN "indefinite" */
- RE_ENTRANT_CHECK_OFF
- verify_area(VERIFY_WRITE,d,10);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,10);
for ( i = 0; i < 7; i++)
put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */
put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
put_fs_byte(0xff, (unsigned char *) d+8);
put_fs_byte(0xff, (unsigned char *) d+9);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
else
@@ -1064,18 +1075,20 @@ int reg_store_bcd(void)
set_precision_flag(precision_loss);
}
- verify_area(VERIFY_WRITE,d,10);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,10);
+ RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 9; i++)
{
b = div_small(&ll, 10);
b |= (div_small(&ll, 10)) << 4;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
put_fs_byte(b,(unsigned char *) d+i);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
}
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
put_fs_byte(sign,(unsigned char *) d+9);
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -1157,7 +1170,8 @@ char *fldenv(void)
unsigned char tag;
int i;
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_READ, s, 0x1c);
control_word = get_fs_word((unsigned short *) s);
partial_status = get_fs_word((unsigned short *) (s+4));
tag_word = get_fs_word((unsigned short *) (s+8));
@@ -1165,7 +1179,7 @@ char *fldenv(void)
cs_selector = get_fs_long((unsigned long *) (s+0x10));
data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
operand_selector = get_fs_long((unsigned long *) (s+0x18));
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
top = (partial_status >> SW_Top_Shift) & 7;
@@ -1275,9 +1289,8 @@ char *fstenv(void)
{
char *d = (char *)FPU_data_address;
- verify_area(VERIFY_WRITE,d,28);
-
- RE_ENTRANT_CHECK_OFF
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,28);
#ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */
put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
@@ -1297,7 +1310,7 @@ char *fstenv(void)
#else
put_fs_long(operand_selector, (unsigned long *) (d+0x18));
#endif PECULIAR_486
- RE_ENTRANT_CHECK_ON
+ RE_ENTRANT_CHECK_ON;
control_word |= CW_Exceptions;
partial_status &= ~(SW_Summary | SW_Backward);
@@ -1312,7 +1325,9 @@ void fsave(void)
int i;
d = fstenv();
- verify_area(VERIFY_WRITE,d,80);
+ RE_ENTRANT_CHECK_OFF;
+ FPU_verify_area(VERIFY_WRITE,d,80);
+ RE_ENTRANT_CHECK_ON;
for ( i = 0; i < 8; i++ )
write_to_extended(&regs[(top + i) & 7], d + 10 * i);
@@ -1324,7 +1339,7 @@ void fsave(void)
/*
A call to this function must be preceeded by a call to
- verify_area() to verify access to the 10 bytes at d
+ FPU_verify_area() to verify access to the 10 bytes at d
*/
static void write_to_extended(FPU_REG *rp, char *d)
{
diff --git a/drivers/FPU-emu/version.h b/drivers/FPU-emu/version.h
index 5ae1f49..807066c 100644
--- a/drivers/FPU-emu/version.h
+++ b/drivers/FPU-emu/version.h
@@ -9,5 +9,5 @@
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version Beta 1.7"
+#define FPU_VERSION "wm-FPU-emu version Beta 1.8"
diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
index 9b9f114..c9952fc 100644
--- a/drivers/char/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 6e3792c..0d7a3be 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
-#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/drivers/char/console.c b/drivers/char/console.c
index c153a74..690250b 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -967,7 +967,6 @@ void con_write(struct tty_struct * tty)
int c;
unsigned int currcons;
- wake_up_interruptible(&tty->write_q.proc_list);
currcons = tty->line - 1;
if (currcons >= NR_CONSOLES) {
printk("con_write: illegal tty (%d)\n", currcons);
@@ -1279,6 +1278,8 @@ void con_write(struct tty_struct * tty)
if (vcmode != KD_GRAPHICS)
set_cursor(currcons);
enable_bh(KEYBOARD_BH);
+ if (LEFT(&tty->write_q) > WAKEUP_CHARS)
+ wake_up_interruptible(&tty->write_q.proc_list);
}
void do_keyboard_interrupt(void)
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index c509482..adec0e5 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -126,6 +126,8 @@ static unsigned char handle_diacr(unsigned char);
/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
static struct pt_regs * pt_regs;
+static int got_break = 0;
+
static inline void kb_wait(void)
{
int i;
@@ -343,7 +345,6 @@ static void put_queue(int ch)
if (LEFT(qp)) {
qp->buf[qp->head] = ch;
INC(qp->head);
- wake_up_interruptible(&qp->proc_list);
}
}
@@ -364,7 +365,6 @@ static void puts_queue(char *cp)
INC(qp->head);
}
}
- wake_up_interruptible(&qp->proc_list);
}
static void applkey(int key, char mode)
@@ -419,13 +419,13 @@ static void hold(void)
{
if (rep || !tty)
return;
- if (vc_kbd_flag(kbd, VC_SCROLLOCK))
- /* pressing srcoll lock 2nd time sends ^Q, ChN */
- put_queue(START_CHAR(tty));
+ /* pressing scroll lock 1st time sends ^S, ChN */
+ /* pressing scroll lock 2nd time sends ^Q, ChN */
+ /* now done directly without regard to ISIG -- jlc */
+ if (!vc_kbd_flag(kbd, VC_SCROLLOCK))
+ stop_tty(tty);
else
- /* pressing scroll lock 1st time sends ^S, ChN */
- put_queue(STOP_CHAR(tty));
- chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
+ start_tty(tty);
}
static void num(void)
@@ -453,8 +453,7 @@ static void lastcons(void)
static void send_intr(void)
{
- if (tty)
- put_queue(INTR_CHAR(tty));
+ got_break = 1;
}
static void scrll_forw(void)
@@ -814,6 +813,26 @@ static void kbd_bh(void * unused)
}
want_console = -1;
}
+ if (got_break) {
+ if (tty && !I_IGNBRK(tty)) {
+ if (I_BRKINT(tty)) {
+ flush_input(tty);
+ flush_output(tty);
+ if (tty->pgrp > 0)
+ kill_pg(tty->pgrp, SIGINT, 1);
+ } else {
+ cli();
+ if (LEFT(&tty->read_q) >= 2) {
+ set_bit(tty->read_q.head,
+ &tty->readq_flags);
+ put_queue(TTY_BREAK);
+ put_queue(0);
+ }
+ sti();
+ }
+ }
+ got_break = 0;
+ }
do_keyboard_interrupt();
cli();
if ((inb_p(0x64) & kbd_read_mask) == 0x01)
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index 8a5bef4..6db02c0 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/busmouse.h>
-#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index f3ee83b..4797597 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -17,17 +17,20 @@
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
+#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
static void pty_close(struct tty_struct * tty, struct file * filp)
{
if (!tty)
return;
if (IS_A_PTY_MASTER(tty->line)) {
if (tty->count > 1)
- return;
+ printk("master pty_close: count = %d!!\n", tty->count);
} else {
if (tty->count > 2)
return;
@@ -40,32 +43,39 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
wake_up_interruptible(&tty->link->secondary.proc_list);
wake_up_interruptible(&tty->link->read_q.proc_list);
wake_up_interruptible(&tty->link->write_q.proc_list);
- if (IS_A_PTY_MASTER(tty->line)) {
+ if (IS_A_PTY_MASTER(tty->line))
tty_hangup(tty->link);
- flush_input(tty);
- flush_output(tty);
+ else {
+ start_tty(tty);
+ set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
}
}
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
{
- int c;
+ unsigned long count, n;
+ struct tty_queue *fq, *tq;
- while (!from->stopped && !EMPTY(&from->write_q)) {
- if (FULL(&to->read_q)) {
- TTY_READ_FLUSH(to);
- if (FULL(&to->read_q))
- break;
- continue;
- }
- c = get_tty_queue(&from->write_q);
- put_tty_queue(c, &to->read_q);
- if (current->signal & ~current->blocked)
- break;
+ if (from->stopped || EMPTY(&from->write_q))
+ return;
+ fq = &from->write_q;
+ /* Bypass the read_q if this is a pty master. */
+ tq = IS_A_PTY_MASTER(to->line) ? &to->secondary : &to->read_q;
+ count = MIN(CHARS(fq), LEFT(tq));
+ while (count) {
+ n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head),
+ count);
+ memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n);
+ count -= n;
+ fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1);
+ tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1);
}
- TTY_READ_FLUSH(to);
- if (!FULL(&from->write_q))
- wake_up_interruptible(&from->write_q.proc_list);
+ if (IS_A_PTY_MASTER(to->line))
+ wake_up_interruptible(&tq->proc_list);
+ else
+ TTY_READ_FLUSH(to);
+ if (LEFT(fq) > WAKEUP_CHARS)
+ wake_up_interruptible(&fq->proc_list);
if (from->write_data_cnt) {
set_bit(from->line, &tty_check_write);
mark_bh(TTY_BH);
@@ -87,10 +97,8 @@ int pty_open(struct tty_struct *tty, struct file * filp)
{
if (!tty || !tty->link)
return -ENODEV;
- if (IS_A_PTY_MASTER(tty->line))
- clear_bit(TTY_SLAVE_OPENED, &tty->flags);
- else
- set_bit(TTY_SLAVE_OPENED, &tty->link->flags);
+ if (IS_A_PTY_SLAVE(tty->line))
+ clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
tty->write = tty->link->write = pty_write;
tty->close = tty->link->close = pty_close;
wake_up_interruptible(&tty->read_q.proc_list);
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index ffb7f93..2b6aa0c 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -58,8 +58,6 @@
#undef ISR_HACK
-#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
-
/*
* rs_event - Bitfield of serial lines that events pending
* to be processed at the next clock tick.
@@ -418,7 +416,7 @@ static inline int check_modem_status(struct async_struct *info)
status = serial_in(info, UART_MSR);
- if ((status & UART_MSR_DDCD) && !C_LOCAL(info->tty)) {
+ if ((status & UART_MSR_DDCD) && !C_CLOCAL(info->tty)) {
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
@@ -433,7 +431,7 @@ static inline int check_modem_status(struct async_struct *info)
rs_sched_event(info, RS_EVENT_HANGUP);
}
}
- if (C_RTSCTS(info->tty)) {
+ if (C_CRTSCTS(info->tty)) {
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
#ifdef SERIAL_DEBUG_INTR
@@ -562,7 +560,7 @@ static inline void handle_rs_break(struct async_struct *info)
if (info->flags & ASYNC_SAK)
do_SAK(info->tty);
- if (I_BRKINT(info->tty)) {
+ if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) {
flush_input(info->tty);
flush_output(info->tty);
if (info->tty->pgrp > 0)
@@ -1066,7 +1064,7 @@ static void rs_throttle(struct tty_struct * tty, int status)
switch (status) {
case TTY_THROTTLE_RQ_FULL:
info = rs_table + DEV_TO_SL(tty->line);
- if (tty->termios->c_iflag & IXOFF) {
+ if (I_IXOFF(tty)) {
info->x_char = STOP_CHAR(tty);
} else {
mcr = serial_inp(info, UART_MCR);
@@ -1076,7 +1074,7 @@ static void rs_throttle(struct tty_struct * tty, int status)
break;
case TTY_THROTTLE_RQ_AVAIL:
info = rs_table + DEV_TO_SL(tty->line);
- if (tty->termios->c_iflag & IXOFF) {
+ if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else
@@ -1382,7 +1380,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
if (error)
return error;
- put_fs_long(C_LOCAL(tty) ? 1 : 0,
+ put_fs_long(C_CLOCAL(tty) ? 1 : 0,
(unsigned long *) arg);
return 0;
case TIOCSSOFTCAR:
@@ -1591,7 +1589,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
{
struct wait_queue wait = { current, NULL };
int retval;
- int do_clocal = C_LOCAL(tty);
+ int do_clocal = C_CLOCAL(tty);
/*
* If the device is in the middle of being closed, then block
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index c07c194..c2da44d 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -32,6 +32,9 @@
* Added functionality to the OPOST tty handling. No delays, but all
* other bits should be there.
* -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
+ *
+ * Rewrote canonical mode and added more termios flags.
+ * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
*/
#include <linux/types.h>
@@ -98,7 +101,7 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
return 0;
}
-void put_tty_queue(char c, struct tty_queue * queue)
+void put_tty_queue(unsigned char c, struct tty_queue * queue)
{
int head;
unsigned long flags;
@@ -121,8 +124,8 @@ int get_tty_queue(struct tty_queue * queue)
save_flags(flags);
cli();
if (queue->tail != queue->head) {
- result = 0xff & queue->buf[queue->tail];
- queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
+ result = queue->buf[queue->tail];
+ INC(queue->tail);
}
restore_flags(flags);
return result;
@@ -499,7 +502,220 @@ void wait_for_keypress(void)
sleep_on(&keypress_wait);
}
-void copy_to_cooked(struct tty_struct * tty)
+void stop_tty(struct tty_struct *tty)
+{
+ if (tty->stopped)
+ return;
+ tty->stopped = 1;
+ if (tty->link && tty->link->packet) {
+ tty->ctrl_status &= ~TIOCPKT_START;
+ tty->ctrl_status |= TIOCPKT_STOP;
+ wake_up_interruptible(&tty->link->secondary.proc_list);
+ }
+ if (tty->stop)
+ (tty->stop)(tty);
+ if (IS_A_CONSOLE(tty->line)) {
+ set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
+ set_leds();
+ }
+}
+
+void start_tty(struct tty_struct *tty)
+{
+ if (!tty->stopped)
+ return;
+ tty->stopped = 0;
+ if (tty->link && tty->link->packet) {
+ tty->ctrl_status &= ~TIOCPKT_STOP;
+ tty->ctrl_status |= TIOCPKT_START;
+ wake_up_interruptible(&tty->link->secondary.proc_list);
+ }
+ if (tty->start)
+ (tty->start)(tty);
+ if (IS_A_CONSOLE(tty->line)) {
+ clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
+ set_leds();
+ }
+ TTY_WRITE_FLUSH(tty);
+}
+
+/* Perform OPOST processing. Returns -1 when the write_q becomes full
+ and the character must be retried. */
+
+static int opost(unsigned char c, struct tty_struct *tty)
+{
+ if (FULL(&tty->write_q))
+ return -1;
+ if (O_OPOST(tty)) {
+ switch (c) {
+ case '\n':
+ if (O_ONLRET(tty))
+ tty->column = 0;
+ if (O_ONLCR(tty)) {
+ if (LEFT(&tty->write_q) < 2)
+ return -1;
+ put_tty_queue('\r', &tty->write_q);
+ tty->column = 0;
+ }
+ tty->canon_column = tty->column;
+ break;
+ case '\r':
+ if (O_ONOCR(tty) && tty->column == 0)
+ return 0;
+ if (O_OCRNL(tty)) {
+ c = '\n';
+ if (O_ONLRET(tty))
+ tty->canon_column = tty->column = 0;
+ break;
+ }
+ tty->canon_column = tty->column = 0;
+ break;
+ case '\t':
+ if (O_TABDLY(tty) == XTABS) {
+ if (LEFT(&tty->write_q) < 8)
+ return -1;
+ do
+ put_tty_queue(' ', &tty->write_q);
+ while (++tty->column % 8);
+ return 0;
+ }
+ tty->column = (tty->column | 7) + 1;
+ break;
+ case '\b':
+ if (tty->column > 0)
+ tty->column--;
+ break;
+ default:
+ if (O_OLCUC(tty))
+ c = toupper(c);
+ if (!iscntrl(c))
+ tty->column++;
+ break;
+ }
+ }
+ put_tty_queue(c, &tty->write_q);
+ return 0;
+}
+
+/* Must be called only when L_ECHO(tty) is true. */
+
+static void echo_char(unsigned char c, struct tty_struct *tty)
+{
+ if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
+ opost('^', tty);
+ opost(c ^ 0100, tty);
+ } else
+ opost(c, tty);
+}
+
+static void eraser(unsigned char c, struct tty_struct *tty)
+{
+ enum { ERASE, WERASE, KILL } kill_type;
+ int seen_alnums;
+
+ if (tty->secondary.head == tty->canon_head) {
+ /* opost('\a', tty); */ /* what do you think? */
+ return;
+ }
+ if (c == ERASE_CHAR(tty))
+ kill_type = ERASE;
+ else if (c == WERASE_CHAR(tty))
+ kill_type = WERASE;
+ else {
+ if (!L_ECHO(tty)) {
+ tty->secondary.head = tty->canon_head;
+ return;
+ }
+ if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
+ tty->secondary.head = tty->canon_head;
+ if (tty->erasing) {
+ opost('/', tty);
+ tty->erasing = 0;
+ }
+ echo_char(KILL_CHAR(tty), tty);
+ /* Add a newline if ECHOK is on and ECHOKE is off. */
+ if (L_ECHOK(tty))
+ opost('\n', tty);
+ return;
+ }
+ kill_type = KILL;
+ }
+
+ seen_alnums = 0;
+ while (tty->secondary.head != tty->canon_head) {
+ c = LAST(&tty->secondary);
+ if (kill_type == WERASE) {
+ /* Equivalent to BSD's ALTWERASE. */
+ if (isalnum(c) || c == '_')
+ seen_alnums++;
+ else if (seen_alnums)
+ break;
+ }
+ DEC(tty->secondary.head);
+ if (L_ECHO(tty)) {
+ if (L_ECHOPRT(tty)) {
+ if (!tty->erasing) {
+ opost('\\', tty);
+ tty->erasing = 1;
+ }
+ echo_char(c, tty);
+ } else if (!L_ECHOE(tty)) {
+ echo_char(ERASE_CHAR(tty), tty);
+ } else if (c == '\t') {
+ unsigned int col = tty->canon_column;
+ unsigned long tail = tty->canon_head;
+
+ /* Find the column of the last char. */
+ while (tail != tty->secondary.head) {
+ c = tty->secondary.buf[tail];
+ if (c == '\t')
+ col = (col | 7) + 1;
+ else if (iscntrl(c)) {
+ if (L_ECHOCTL(tty))
+ col += 2;
+ } else
+ col++;
+ INC(tail);
+ }
+
+ /* Now backup to that column. */
+ while (tty->column > col) {
+ /* Can't use opost here. */
+ put_tty_queue('\b', &tty->write_q);
+ tty->column--;
+ }
+ } else {
+ if (iscntrl(c) && L_ECHOCTL(tty)) {
+ opost('\b', tty);
+ opost(' ', tty);
+ opost('\b', tty);
+ }
+ if (!iscntrl(c) || L_ECHOCTL(tty)) {
+ opost('\b', tty);
+ opost(' ', tty);
+ opost('\b', tty);
+ }
+ }
+ }
+ if (kill_type == ERASE)
+ break;
+ }
+ if (tty->erasing && tty->secondary.head == tty->canon_head) {
+ opost('/', tty);
+ tty->erasing = 0;
+ }
+}
+
+static void isig(int sig, struct tty_struct *tty)
+{
+ kill_pg(tty->pgrp, sig, 1);
+ if (!L_NOFLSH(tty)) {
+ flush_input(tty);
+ flush_output(tty);
+ }
+}
+
+static void copy_to_cooked(struct tty_struct * tty)
{
int c, special_flag;
unsigned long flags;
@@ -525,19 +741,18 @@ void copy_to_cooked(struct tty_struct * tty)
if (c == 0)
break;
save_flags(flags); cli();
- if (tty->read_q.tail != tty->read_q.head) {
- c = 0xff & tty->read_q.buf[tty->read_q.tail];
+ if (!EMPTY(&tty->read_q)) {
+ c = tty->read_q.buf[tty->read_q.tail];
special_flag = clear_bit(tty->read_q.tail,
- &tty->readq_flags);
- tty->read_q.tail = (tty->read_q.tail + 1) &
- (TTY_BUF_SIZE-1);
+ &tty->readq_flags);
+ INC(tty->read_q.tail);
restore_flags(flags);
} else {
restore_flags(flags);
break;
}
if (special_flag) {
- tty->char_error = c & 7;
+ tty->char_error = c;
continue;
}
if (tty->char_error) {
@@ -545,6 +760,9 @@ void copy_to_cooked(struct tty_struct * tty)
tty->char_error = 0;
if (I_IGNBRK(tty))
continue;
+ /* A break is handled by the lower levels. */
+ if (I_BRKINT(tty))
+ continue;
if (I_PARMRK(tty)) {
put_tty_queue('\377', &tty->secondary);
put_tty_queue('\0', &tty->secondary);
@@ -570,157 +788,131 @@ void copy_to_cooked(struct tty_struct * tty)
put_tty_queue('\0', &tty->secondary);
continue;
}
- if (I_STRP(tty))
+ if (I_ISTRIP(tty))
c &= 0x7f;
- else if (I_PARMRK(tty) && (c == '\377'))
- put_tty_queue('\377', &tty->secondary);
- if (c==13) {
- if (I_CRNL(tty))
- c=10;
- else if (I_NOCR(tty))
- continue;
- } else if (c==10 && I_NLCR(tty))
- c=13;
- if (I_UCLC(tty))
+ if (!tty->lnext) {
+ if (c == '\r') {
+ if (I_IGNCR(tty))
+ continue;
+ if (I_ICRNL(tty))
+ c = '\n';
+ } else if (c == '\n' && I_INLCR(tty))
+ c = '\r';
+ }
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
c=tolower(c);
if (c == __DISABLED_CHAR)
tty->lnext = 1;
- if (L_CANON(tty) && !tty->lnext) {
- if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || c == WERASE_CHAR(tty)) {
- int seen_alnums =
- (c == WERASE_CHAR(tty)) ? 0 : -1;
- int cc;
-
- /* deal with killing in the input line */
- while(!(EMPTY(&tty->secondary) ||
- (cc=LAST(&tty->secondary))==10 ||
- ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
- (cc==EOF_CHAR(tty))))) {
- /* if killing just a word, kill all
- non-alnum chars, then all alnum
- chars. */
- if (seen_alnums >= 0) {
- if (isalnum(cc))
- seen_alnums++;
- else if (seen_alnums)
- break;
+ if (L_ICANON(tty) && !tty->lnext) {
+ if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
+ (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
+ eraser(c, tty);
+ continue;
+ }
+ if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
+ tty->lnext = 1;
+ if (L_ECHO(tty)) {
+ if (tty->erasing) {
+ opost('/', tty);
+ tty->erasing = 0;
}
- if (L_ECHO(tty)) {
- int ct = 1;
- if (cc < 32)
- ct = (L_ECHOCTL(tty) ? 2 : 0);
- while(ct--) {
- put_tty_queue('\b', &tty->write_q);
- put_tty_queue(' ', &tty->write_q);
- put_tty_queue('\b',&tty->write_q);
- }
+ if (L_ECHOCTL(tty)) {
+ opost('^', tty);
+ opost('\b', tty);
}
- DEC(tty->secondary.head);
- if(c == ERASE_CHAR(tty))
- break;
}
continue;
}
- if (c == LNEXT_CHAR(tty)) {
- tty->lnext = 1;
- if (L_ECHO(tty)) {
- put_tty_queue('^',&tty->write_q);
- put_tty_queue('\b',&tty->write_q);
+ if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
+ L_IEXTEN(tty)) {
+ unsigned long tail = tty->canon_head;
+
+ if (tty->erasing) {
+ opost('/', tty);
+ tty->erasing = 0;
+ }
+ echo_char(c, tty);
+ opost('\n', tty);
+ while (tail != tty->secondary.head) {
+ echo_char(tty->secondary.buf[tail],
+ tty);
+ INC(tail);
}
continue;
}
}
if (I_IXON(tty) && !tty->lnext) {
- if (c == STOP_CHAR(tty)) {
- tty->ctrl_status &= ~(TIOCPKT_START);
- tty->ctrl_status |= TIOCPKT_STOP;
- if (tty->link)
- wake_up_interruptible(&tty->link->except_q);
- tty->stopped=1;
- if (tty->stop)
- (tty->stop)(tty);
- if (IS_A_CONSOLE(tty->line)) {
- set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
- set_leds();
- }
+ if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) ||
+ c == START_CHAR(tty)) {
+ start_tty(tty);
continue;
}
- if (((I_IXANY(tty)) && tty->stopped) ||
- (c == START_CHAR(tty))) {
- tty->ctrl_status &= ~(TIOCPKT_STOP);
- tty->ctrl_status |= TIOCPKT_START;
- tty->stopped=0;
- if (tty->link)
- wake_up_interruptible(&tty->link->except_q);
- if (tty->start)
- (tty->start)(tty);
- if (IS_A_CONSOLE(tty->line)) {
- clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
- set_leds();
- }
+ if (c == STOP_CHAR(tty)) {
+ stop_tty(tty);
continue;
}
}
if (L_ISIG(tty) && !tty->lnext) {
if (c == INTR_CHAR(tty)) {
- kill_pg(tty->pgrp, SIGINT, 1);
- if (! _L_FLAG(tty, NOFLSH)) {
- flush_input(tty);
- flush_output(tty);
- }
+ isig(SIGINT, tty);
continue;
}
if (c == QUIT_CHAR(tty)) {
- kill_pg(tty->pgrp, SIGQUIT, 1);
- if (! _L_FLAG(tty, NOFLSH)) {
- flush_input(tty);
- flush_output(tty);
- }
+ isig(SIGQUIT, tty);
continue;
}
- if (c == SUSPEND_CHAR(tty)) {
- if (!is_orphaned_pgrp(tty->pgrp)) {
- kill_pg(tty->pgrp, SIGTSTP, 1);
- if (! _L_FLAG(tty, NOFLSH)) {
- flush_input(tty);
- flush_output(tty);
- }
- }
+ if (c == SUSP_CHAR(tty)) {
+ if (!is_orphaned_pgrp(tty->pgrp))
+ isig(SIGTSTP, tty);
continue;
}
}
- if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR &&
- c==EOF_CHAR(tty)))
- tty->secondary.data++;
- if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) {
- put_tty_queue('\n',&tty->write_q);
- put_tty_queue('\r',&tty->write_q);
+
+ if (tty->erasing) {
+ opost('/', tty);
+ tty->erasing = 0;
+ }
+ if (c == '\n' && !tty->lnext) {
+ if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty)))
+ opost('\n', tty);
} else if (L_ECHO(tty)) {
- if (c<32 && L_ECHOCTL(tty)) {
- put_tty_queue('^',&tty->write_q);
- put_tty_queue(c+'A'-1, &tty->write_q);
- if (EOF_CHAR(tty) != __DISABLED_CHAR &&
- c==EOF_CHAR(tty) && !tty->lnext) {
- put_tty_queue('\b',&tty->write_q);
- put_tty_queue('\b',&tty->write_q);
- }
- } else
- put_tty_queue(c, &tty->write_q);
+ /* Don't echo the EOF char in canonical mode. Sun
+ handles this differently by echoing the char and
+ then backspacing, but that's a hack. */
+ if (c != EOF_CHAR(tty) || !L_ICANON(tty) ||
+ tty->lnext) {
+ /* Record the column of first canon char. */
+ if (tty->canon_head == tty->secondary.head)
+ tty->canon_column = tty->column;
+ echo_char(c, tty);
+ }
}
+
+ if (I_PARMRK(tty) && c == (unsigned char) '\377' &&
+ (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext))
+ put_tty_queue(c, &tty->secondary);
+
+ if (L_ICANON(tty) && !tty->lnext &&
+ (c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) ||
+ (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) {
+ if (c == EOF_CHAR(tty))
+ c = __DISABLED_CHAR;
+ set_bit(tty->secondary.head, &tty->secondary_flags);
+ put_tty_queue(c, &tty->secondary);
+ tty->canon_head = tty->secondary.head;
+ tty->canon_data++;
+ } else
+ put_tty_queue(c, &tty->secondary);
tty->lnext = 0;
- put_tty_queue(c, &tty->secondary);
}
- TTY_WRITE_FLUSH(tty);
- if (!EMPTY(&tty->secondary))
+ if (!EMPTY(&tty->write_q))
+ TTY_WRITE_FLUSH(tty);
+ if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
wake_up_interruptible(&tty->secondary.proc_list);
- if (tty->write_q.proc_list && LEFT(&tty->write_q) > TTY_BUF_SIZE/2)
- wake_up_interruptible(&tty->write_q.proc_list);
+
if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
&& clear_bit(TTY_RQ_THROTTLED, &tty->flags))
tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
- if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
- && clear_bit(TTY_SQ_THROTTLED, &tty->flags))
- tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
}
int is_ignored(int sig)
@@ -729,278 +921,205 @@ int is_ignored(int sig)
(current->sigaction[sig-1].sa_handler == SIG_IGN));
}
-static int available_canon_input(struct tty_struct *);
-static void __wait_for_canon_input(struct file * file, struct tty_struct *);
-
-static void wait_for_canon_input(struct file * file, struct tty_struct * tty)
+static inline int input_available_p(struct tty_struct *tty)
{
- if (!available_canon_input(tty)) {
- if (current->signal & ~current->blocked)
- return;
- __wait_for_canon_input(file, tty);
- }
+ /* Avoid calling TTY_READ_FLUSH unnecessarily. */
+ if (L_ICANON(tty)) {
+ if (tty->canon_data || FULL(&tty->read_q))
+ return 1;
+ } else if (!EMPTY(&tty->secondary))
+ return 1;
+
+ /* Shuffle any pending data down the queues. */
+ TTY_READ_FLUSH(tty);
+ if (tty->link)
+ TTY_WRITE_FLUSH(tty->link);
+
+ if (L_ICANON(tty)) {
+ if (tty->canon_data || FULL(&tty->read_q))
+ return 1;
+ } else if (!EMPTY(&tty->secondary))
+ return 1;
+ return 0;
}
-static int read_chan(struct tty_struct * tty, struct file * file, char * buf, int nr)
+static int read_chan(struct tty_struct *tty, struct file *file,
+ unsigned char *buf, unsigned int nr)
{
struct wait_queue wait = { current, NULL };
int c;
- char * b=buf;
- int minimum,time;
+ unsigned char *b = buf;
+ int minimum, time;
+ int retval = 0;
- if (L_CANON(tty))
- minimum = time = current->timeout = 0;
- else {
- time = 10L*tty->termios->c_cc[VTIME];
- minimum = tty->termios->c_cc[VMIN];
+ if (L_ICANON(tty)) {
+ minimum = time = 0;
+ current->timeout = (unsigned long) -1;
+ } else {
+ time = (HZ / 10) * TIME_CHAR(tty);
+ minimum = MIN_CHAR(tty);
if (minimum)
- current->timeout = 0xffffffff;
+ current->timeout = (unsigned long) -1;
else {
- if (time)
+ if (time) {
current->timeout = time + jiffies;
- else
+ time = 0;
+ } else
current->timeout = 0;
- time = 0;
minimum = 1;
}
}
- if (file->f_flags & O_NONBLOCK) {
- time = current->timeout = 0;
- if (L_CANON(tty) && !available_canon_input(tty))
- return -EAGAIN;
- } else if (L_CANON(tty)) {
- wait_for_canon_input(file, tty);
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- }
- if (minimum>nr)
- minimum = nr;
- /* deal with packet mode: First test for status change */
- if (tty->packet && tty->link && tty->link->ctrl_status) {
- put_fs_byte (tty->link->ctrl_status, b);
- tty->link->ctrl_status = 0;
- return 1;
- }
-
- /* now bump the buffer up one. */
- if (tty->packet) {
- put_fs_byte (0,b++);
- nr--;
- /* this really shouldn't happen, but we need to
- put it here. */
- if (nr == 0)
- return 1;
- }
add_wait_queue(&tty->secondary.proc_list, &wait);
- while (nr>0) {
- if (tty_hung_up_p(file)) {
- file->f_flags &= ~O_NONBLOCK;
- break; /* force read() to return 0 */
- }
- TTY_READ_FLUSH(tty);
- if (tty->link)
- TTY_WRITE_FLUSH(tty->link);
- while (nr > 0 && ((c = get_tty_queue(&tty->secondary)) >= 0)) {
- if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
- c==EOF_CHAR(tty)) || c==10)
- tty->secondary.data--;
- if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
- c==EOF_CHAR(tty)) && L_CANON(tty))
- break;
- put_fs_byte(c,b++);
- nr--;
- if (time)
- current->timeout = time+jiffies;
- if (c==10 && L_CANON(tty))
- break;
- };
- wake_up_interruptible(&tty->read_q.proc_list);
- /*
- * If there is enough space in the secondary queue
- * now, let the low-level driver know.
- */
- if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
- && clear_bit(TTY_SQ_THROTTLED, &tty->flags))
- tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
- if (tty->link) {
- if (IS_A_PTY_MASTER(tty->line)) {
- if ((tty->flags & (1 << TTY_SLAVE_OPENED))
- && tty->link->count <= 1) {
- file->f_flags &= ~O_NONBLOCK;
+ while (1) {
+ /* Job control check -- must be done at start and after
+ every sleep (POSIX.1 7.1.1.4). */
+ /* don't stop on /dev/console */
+ if (file->f_inode->i_rdev != CONSOLE_DEV &&
+ current->tty == tty->line) {
+ if (tty->pgrp <= 0)
+ printk("read_chan: tty->pgrp <= 0!\n");
+ else if (current->pgrp != tty->pgrp) {
+ if (is_ignored(SIGTTIN) ||
+ is_orphaned_pgrp(current->pgrp)) {
+ retval = -EIO;
break;
}
- } else if (!tty->link->count) {
- file->f_flags &= ~O_NONBLOCK;
+ kill_pg(current->pgrp, SIGTTIN, 1);
+ retval = -ERESTARTSYS;
break;
}
}
- if (b-buf >= minimum || !current->timeout)
- break;
- if (current->signal & ~current->blocked)
+ /* First test for status change. */
+ if (tty->packet && tty->link->ctrl_status) {
+ if (b != buf)
+ break;
+ put_fs_byte(tty->link->ctrl_status, b++);
+ tty->link->ctrl_status = 0;
break;
- TTY_READ_FLUSH(tty);
- if (tty->link)
- TTY_WRITE_FLUSH(tty->link);
- if (!EMPTY(&tty->secondary))
- continue;
+ }
+ /* This statement must be first before checking for input
+ so that any interrupt will set the state back to
+ TASK_RUNNING. */
current->state = TASK_INTERRUPTIBLE;
- if (EMPTY(&tty->secondary))
+ if (!input_available_p(tty)) {
+ if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
+ retval = -EIO;
+ break;
+ }
+ if (tty_hung_up_p(file))
+ break;
+ if (!current->timeout)
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
schedule();
+ continue;
+ }
current->state = TASK_RUNNING;
- }
- remove_wait_queue(&tty->secondary.proc_list, &wait);
- TTY_READ_FLUSH(tty);
- if (tty->link && tty->link->write)
- TTY_WRITE_FLUSH(tty->link);
- current->timeout = 0;
- /* packet mode sticks in an extra 0. If that's all we've got,
- we should count it a zero bytes. */
- if (tty->packet) {
- if ((b-buf) > 1)
- return b-buf;
- } else {
- if (b-buf)
- return b-buf;
- }
+ /* Deal with packet mode. */
+ if (tty->packet && b == buf) {
+ put_fs_byte(TIOCPKT_DATA, b++);
+ nr--;
+ }
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- if (IS_A_PTY_MASTER(tty->line))
- return -EIO;
- return 0;
-}
+ while (nr > 0) {
+ int eol;
-static void __wait_for_canon_input(struct file * file, struct tty_struct * tty)
-{
- struct wait_queue wait = { current, NULL };
+ cli();
+ if (EMPTY(&tty->secondary)) {
+ sti();
+ break;
+ }
+ eol = clear_bit(tty->secondary.tail,
+ &tty->secondary_flags);
+ c = tty->secondary.buf[tty->secondary.tail];
+ INC(tty->secondary.tail);
+ sti();
+ if (eol) {
+ if (--tty->canon_data < 0) {
+ printk("read_chan: canon_data < 0!\n");
+ tty->canon_data = 0;
+ }
+ if (c == __DISABLED_CHAR)
+ break;
+ put_fs_byte(c, b++);
+ nr--;
+ break;
+ }
+ put_fs_byte(c, b++);
+ nr--;
+ }
- add_wait_queue(&tty->secondary.proc_list, &wait);
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- if (available_canon_input(tty))
- break;
- if (current->signal & ~current->blocked)
- break;
- if (tty_hung_up_p(file))
+ /* If there is enough space in the secondary queue now, let the
+ low-level driver know. */
+ if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
+ && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
+ tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
+
+ /* XXX packet mode's status byte is mistakenly counted */
+ if (b - buf >= minimum || !nr)
break;
- schedule();
+ if (time)
+ current->timeout = time + jiffies;
}
- current->state = TASK_RUNNING;
remove_wait_queue(&tty->secondary.proc_list, &wait);
+ current->state = TASK_RUNNING;
+ current->timeout = 0;
+ return (b - buf) ? b - buf : retval;
}
-static int available_canon_input(struct tty_struct * tty)
-{
- TTY_READ_FLUSH(tty);
- if (tty->link)
- if (tty->link->count)
- TTY_WRITE_FLUSH(tty->link);
- else
- return 1;
- if (FULL(&tty->read_q))
- return 1;
- if (tty->secondary.data)
- return 1;
- return 0;
-}
-
-static int write_chan(struct tty_struct * tty, struct file * file, char * buf, int nr)
+static int write_chan(struct tty_struct * tty, struct file * file,
+ unsigned char * buf, unsigned int nr)
{
struct wait_queue wait = { current, NULL };
- char c, *b=buf;
+ int c;
+ unsigned char *b = buf;
+ int retval = 0;
+
+ /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+ if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
+ retval = check_change(tty, tty->line);
+ if (retval)
+ return retval;
+ }
- if (nr < 0)
- return -EINVAL;
- if (!nr)
- return 0;
add_wait_queue(&tty->write_q.proc_list, &wait);
- while (nr>0) {
- if (current->signal & ~current->blocked)
- break;
- if (tty_hung_up_p(file))
- break;
- if (tty->link && !tty->link->count) {
- send_sig(SIGPIPE,current,0);
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
break;
}
- current->state = TASK_INTERRUPTIBLE;
- if (FULL(&tty->write_q)) {
- TTY_WRITE_FLUSH(tty);
- if (FULL(&tty->write_q))
- schedule();
- current->state = TASK_RUNNING;
- continue;
+ if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
+ retval = -EIO;
+ break;
}
- current->state = TASK_RUNNING;
- while (nr>0 && !FULL(&tty->write_q)) {
- c=get_fs_byte(b);
- if (O_POST(tty)) {
- switch (c) {
- case '\n':
- if (O_NLRET(tty)) {
- tty->column = 0;
- }
- if (O_NLCR(tty)) {
- if (!set_bit(TTY_CR_PENDING,&tty->flags)) {
- c = '\r';
- tty->column = 0;
- b--; nr++;
- } else {
- clear_bit(TTY_CR_PENDING,&tty->flags);
- }
- }
- break;
- case '\r':
- if (O_NOCR(tty) && tty->column == 0) {
- b++; nr--;
- continue;
- }
- if (O_CRNL(tty)) {
- c = '\n';
- if (O_NLRET(tty))
- tty->column = 0;
- break;
- }
- tty->column = 0;
- break;
- case '\t':
- if (O_TABDLY(tty) == XTABS) {
- c = ' ';
- tty->column++;
- if (tty->column % 8 != 0) {
- b--; nr++;
- }
- }
- break;
- case '\b':
- tty->column--;
- break;
- default:
- if (O_LCUC(tty))
- c = toupper(c);
- tty->column++;
- break;
- }
- }
+ while (nr > 0) {
+ c = get_fs_byte(b);
+ /* Care is needed here: opost() can abort even
+ if the write_q is not full. */
+ if (opost(c, tty) < 0)
+ break;
b++; nr--;
- put_tty_queue(c,&tty->write_q);
}
- if (need_resched)
- schedule();
+ TTY_WRITE_FLUSH(tty);
+ if (!nr)
+ break;
+ if (EMPTY(&tty->write_q) && !need_resched)
+ continue;
+ schedule();
}
+ current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_q.proc_list, &wait);
- TTY_WRITE_FLUSH(tty);
- if (b-buf)
- return b-buf;
- if (tty->link && !tty->link->count)
- return -EPIPE;
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- return 0;
+ return (b - buf) ? b - buf : retval;
}
static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
@@ -1017,6 +1136,12 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
tty = TTY_TABLE(dev);
if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
return -EIO;
+
+ /* This check not only needs to be done before reading, but also
+ whenever read_chan() gets woken up after sleeping, so I've
+ moved it to there. This should only be done for the N_TTY
+ line discipline, anyway. Same goes for write_chan(). -- jlc. */
+#if 0
if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
(tty->pgrp > 0) &&
(current->tty == dev) &&
@@ -1027,8 +1152,10 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
(void) kill_pg(current->pgrp, SIGTTIN, 1);
return -ERESTARTSYS;
}
+#endif
if (ldiscs[tty->disc].read)
- i = (ldiscs[tty->disc].read)(tty,file,buf,count);
+ /* XXX casts are for what kernel-wide prototypes should be. */
+ i = (ldiscs[tty->disc].read)(tty,file,(unsigned char *)buf,(unsigned int)count);
else
i = -EIO;
if (i > 0)
@@ -1054,6 +1181,7 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
tty = TTY_TABLE(dev);
if (!tty || !tty->write || (tty->flags & (1 << TTY_IO_ERROR)))
return -EIO;
+#if 0
if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
(current->tty == dev) && (tty->pgrp != current->pgrp)) {
if (is_orphaned_pgrp(current->pgrp))
@@ -1063,8 +1191,10 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
return -ERESTARTSYS;
}
}
+#endif
if (ldiscs[tty->disc].write)
- i = (ldiscs[tty->disc].write)(tty,file,buf,count);
+ /* XXX casts are for what kernel-wide prototypes should be. */
+ i = (ldiscs[tty->disc].write)(tty,file,(unsigned char *)buf,(unsigned int)count);
else
i = -EIO;
if (i > 0)
@@ -1349,6 +1479,7 @@ retry_open:
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser())
return -EBUSY;
+#if 0
/* clean up the packet stuff. */
/*
* Why is this not done in init_dev? Right here, if another
@@ -1358,9 +1489,12 @@ retry_open:
*
* Not to worry, a pty master can only be opened once.
* And rlogind and telnetd both use packet mode. -- jrs
+ *
+ * Not needed. These are cleared in initialize_tty_struct. -- jlc
*/
tty->ctrl_status = 0;
tty->packet = 0;
+#endif
if (tty->open) {
retval = tty->open(tty, filp);
@@ -1441,26 +1575,16 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
{
switch (sel_type) {
case SEL_IN:
- if (L_CANON(tty)) {
- if (available_canon_input(tty))
- return 1;
- } else if (!EMPTY(&tty->secondary))
+ if (input_available_p(tty))
return 1;
- if (tty->link) {
- if (IS_A_PTY_MASTER(tty->line)) {
- if ((tty->flags & (1 << TTY_SLAVE_OPENED))
- && tty->link->count <= 1)
- return 1;
- } else {
- if (!tty->link->count)
- return 1;
- }
- }
-
- /* see if the status byte can be read. */
- if (tty->packet && tty->link && tty->link->ctrl_status)
+ /* fall through */
+ case SEL_EX:
+ if (tty->packet && tty->link->ctrl_status)
+ return 1;
+ if (tty->flags & (1 << TTY_SLAVE_CLOSED))
+ return 1;
+ if (tty_hung_up_p(file))
return 1;
-
select_wait(&tty->secondary.proc_list, wait);
return 0;
case SEL_OUT:
@@ -1468,22 +1592,6 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
return 1;
select_wait(&tty->write_q.proc_list, wait);
return 0;
- case SEL_EX:
- if (tty->link) {
- if (IS_A_PTY_MASTER(tty->line)) {
- if ((tty->flags & (1 << TTY_SLAVE_OPENED))
- && tty->link->count <= 1)
- return 1;
- if (tty->packet
- && tty->link->ctrl_status)
- return 1;
- } else {
- if (!tty->link->count)
- return 1;
- }
- }
- select_wait(&tty->except_q, wait);
- return 0;
}
return 0;
}
@@ -1645,8 +1753,6 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
tty->line = line;
tty->disc = N_TTY;
tty->pgrp = -1;
- tty->winsize.ws_row = 0;
- tty->winsize.ws_col = 0;
if (IS_A_CONSOLE(line)) {
tty->open = con_open;
tty->winsize.ws_row = video_num_lines;
@@ -1656,31 +1762,26 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
} else if IS_A_PTY(line) {
tty->open = pty_open;
}
- tty->except_q = NULL;
}
static void initialize_termios(int line, struct termios * tp)
{
memset(tp, 0, sizeof(struct termios));
memcpy(tp->c_cc, INIT_C_CC, NCCS);
- if (IS_A_CONSOLE(line)) {
+ if (IS_A_CONSOLE(line) || IS_A_PTY_SLAVE(line)) {
tp->c_iflag = ICRNL | IXON;
tp->c_oflag = OPOST | ONLCR;
tp->c_cflag = B38400 | CS8 | CREAD;
- tp->c_lflag = ISIG | ICANON | ECHO |
- ECHOCTL | ECHOKE;
+ tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
+ ECHOCTL | ECHOKE | IEXTEN;
} else if (IS_A_SERIAL(line)) {
- tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tp->c_iflag = ICRNL | IXON;
tp->c_oflag = OPOST | ONLCR | XTABS;
- } else if (IS_A_PTY_MASTER(line)) {
+ tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
+ ECHOCTL | ECHOKE | IEXTEN;
+ } else if (IS_A_PTY_MASTER(line))
tp->c_cflag = B9600 | CS8 | CREAD;
- } else if (IS_A_PTY_SLAVE(line)) {
- tp->c_iflag = ICRNL | IXON;
- tp->c_oflag = OPOST | ONLCR;
- tp->c_cflag = B38400 | CS8 | CREAD;
- tp->c_lflag = ISIG | ICANON | ECHO |
- ECHOCTL | ECHOKE;
- }
}
static struct tty_ldisc tty_ldisc_N_TTY = {
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index b6d7b48..8f4a744 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -17,6 +17,7 @@
#include <linux/major.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
+#include <linux/string.h>
#include <asm/io.h>
#include <asm/bitops.h>
@@ -41,44 +42,43 @@ extern int paste_selection(struct tty_struct *tty);
static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
-static void flush(struct tty_queue * queue)
-{
- if (queue) {
- cli();
- queue->head = queue->tail;
- sti();
- wake_up_interruptible(&queue->proc_list);
- }
-}
-
void flush_input(struct tty_struct * tty)
{
- tty->ctrl_status |= TIOCPKT_FLUSHREAD;
- if (tty->link)
- wake_up_interruptible(&tty->link->except_q);
- flush(&tty->read_q);
- wake_up_interruptible(&tty->read_q.proc_list);
- flush(&tty->secondary);
- tty->secondary.data = 0;
-
- if ((tty = tty->link) != NULL) {
- flush(&tty->write_q);
- wake_up_interruptible(&tty->write_q.proc_list);
+ cli();
+ tty->read_q.head = tty->read_q.tail = 0;
+ tty->secondary.head = tty->secondary.tail = 0;
+ tty->canon_head = tty->canon_data = tty->erasing = 0;
+ memset(&tty->readq_flags, 0, sizeof tty->readq_flags);
+ memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
+ sti();
+ if (!tty->link)
+ return;
+ /* No cli() since ptys don't use interrupts. */
+ tty->link->write_q.head = tty->link->write_q.tail = 0;
+ wake_up_interruptible(&tty->link->write_q.proc_list);
+ if (tty->link->packet) {
+ tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+ wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
void flush_output(struct tty_struct * tty)
{
- tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
- if (tty->link)
- wake_up_interruptible(&tty->link->except_q);
- flush(&tty->write_q);
+ cli();
+ tty->write_q.head = tty->write_q.tail = 0;
+ sti();
wake_up_interruptible(&tty->write_q.proc_list);
- if ((tty = tty->link) != NULL) {
- flush(&tty->read_q);
- wake_up_interruptible(&tty->read_q.proc_list);
- flush(&tty->secondary);
- tty->secondary.data = 0;
+ if (!tty->link)
+ return;
+ /* No cli() since ptys don't use interrupts. */
+ tty->link->read_q.head = tty->link->read_q.tail = 0;
+ tty->link->secondary.head = tty->link->secondary.tail = 0;
+ tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0;
+ memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags);
+ memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags);
+ if (tty->link->packet) {
+ tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+ wake_up_interruptible(&tty->link->secondary.proc_list);
}
}
@@ -156,65 +156,61 @@ static void unset_locked_termios(struct termios *termios,
old->c_cc[i] : termios->c_cc[i];
}
-static int get_termios(struct tty_struct * tty, struct termios * termios)
-{
- int i;
-
- i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
- if (i)
- return i;
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios );
- return 0;
-}
-
-static int check_change(struct tty_struct * tty, int channel)
+int check_change(struct tty_struct * tty, int channel)
{
/* If we try to set the state of terminal and we're not in the
foreground, send a SIGTTOU. If the signal is blocked or
ignored, go ahead and perform the operation. POSIX 7.2) */
if (current->tty != channel)
return 0;
- if (tty->pgrp <= 0 || tty->pgrp == current->pgrp)
+ if (tty->pgrp <= 0) {
+ printk("check_change: tty->pgrp <= 0!\n");
+ return 0;
+ }
+ if (current->pgrp == tty->pgrp)
return 0;
- if (is_orphaned_pgrp(current->pgrp))
- return -EIO;
if (is_ignored(SIGTTOU))
return 0;
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO;
(void) kill_pg(current->pgrp,SIGTTOU,1);
return -ERESTARTSYS;
}
-static int set_termios(struct tty_struct * tty, struct termios * termios,
- int channel)
+static int set_termios_2(struct tty_struct * tty, struct termios * termios)
{
- int i, old_flow, new_flow;
struct termios old_termios = *tty->termios;
-
- i = check_change(tty, channel);
- if (i)
- return i;
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
+ int canon_change;
+
+ canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
+ cli();
+ *tty->termios = *termios;
+ if (canon_change) {
+ memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
+ tty->canon_head = tty->secondary.tail;
+ tty->canon_data = 0;
+ tty->erasing = 0;
+ }
+ sti();
+ if (canon_change && !(tty->termios->c_lflag & ICANON) &&
+ !EMPTY(&tty->secondary))
+ /* Get characters left over from canonical mode. */
+ wake_up_interruptible(&tty->secondary.proc_list);
/* see if packet mode change of state */
- old_flow = (old_termios.c_iflag & IXON) &&
- (old_termios.c_cc[VSTOP] == '\023') &&
- (old_termios.c_cc[VSTART] == '\021');
-
- new_flow = (tty->termios->c_iflag & IXON) &&
- (tty->termios->c_cc[VSTOP] == '\023') &&
- (tty->termios->c_cc[VSTART] == '\021');
-
- if (old_flow != new_flow) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
- if (new_flow)
+ /* The BSD man page pty.4 says that TIOCPKT_NOSTOP should be sent
+ if the new state differs from ^S/^Q, but that's a bad way of
+ detecting a new flow control scheme. Instead, a status byte
+ is only sent if IXON has changed. */
+ if (tty->link && tty->link->packet &&
+ (old_termios.c_iflag ^ tty->termios->c_iflag) & IXON) {
+ tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ if (tty->termios->c_iflag & IXON)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
- if (tty->link)
- wake_up_interruptible(&tty->link->except_q);
+ tty->ctrl_status |= TIOCPKT_NOSTOP;
+ wake_up_interruptible(&tty->link->secondary.proc_list);
}
#if 0
@@ -241,12 +237,21 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
return 0;
}
+static int set_termios(struct tty_struct * tty, struct termios * termios,
+ int channel)
+{
+ struct termios tmp_termios;
+
+ memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
+ return set_termios_2(tty, &tmp_termios);
+}
+
static int get_termio(struct tty_struct * tty, struct termio * termio)
{
int i;
struct termio tmp_termio;
- i = verify_area(VERIFY_WRITE, termio, sizeof (*termio));
+ i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
if (i)
return i;
tmp_termio.c_iflag = tty->termios->c_iflag;
@@ -256,128 +261,41 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
tmp_termio.c_line = tty->termios->c_line;
for(i=0 ; i < NCC ; i++)
tmp_termio.c_cc[i] = tty->termios->c_cc[i];
- for (i=0 ; i< (sizeof (*termio)) ; i++)
- put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
+ memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
return 0;
}
static int set_termio(struct tty_struct * tty, struct termio * termio,
- int channel)
+ int channel)
{
- int i, old_flow, new_flow;
struct termio tmp_termio;
- struct termios old_termios = *tty->termios;
+ struct termios tmp_termios;
-#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
-
- i = check_change(tty, channel);
- if (i)
- return i;
- memcpy_fromfs(&tmp_termio, termio, sizeof(*termio));
-
- SET_LOW_BITS(tty->termios->c_iflag, tmp_termio.c_iflag);
- SET_LOW_BITS(tty->termios->c_oflag, tmp_termio.c_oflag);
- SET_LOW_BITS(tty->termios->c_cflag, tmp_termio.c_cflag);
- SET_LOW_BITS(tty->termios->c_lflag, tmp_termio.c_lflag);
- memcpy(tty->termios->c_cc, tmp_termio.c_cc, NCC);
-
- /* see if packet mode change of state */
-
- old_flow = (old_termios.c_iflag & IXON) &&
- (old_termios.c_cc[VSTOP] == '\023') &&
- (old_termios.c_cc[VSTART] == '\021');
-
- new_flow = (tty->termios->c_iflag & IXON) &&
- (tty->termios->c_cc[VSTOP] == '\023') &&
- (tty->termios->c_cc[VSTART] == '\021');
+ tmp_termios = *tty->termios;
+ memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
- if (old_flow != new_flow) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
- if (new_flow)
- tty->ctrl_status |= TIOCPKT_DOSTOP;
- else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
- if (tty->link)
- wake_up_interruptible(&tty->link->except_q);
- }
-
- unset_locked_termios(tty->termios, &old_termios,
- termios_locked[tty->line]);
-
-#if 0
- retval = tty_set_ldisc(tty, tmp_termio.c_line);
- if (retval)
- return retval;
-#endif
-
- if (tty->set_termios)
- (*tty->set_termios)(tty, &old_termios);
-
- return 0;
-}
-
-static int get_lcktrmios(struct tty_struct * tty, struct termios * termios,
- int channel)
-{
- int i;
-
- i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
- if (i)
- return i;
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- put_fs_byte( ((char *)termios_locked[channel])[i],
- i+(char *)termios);
- return 0;
-}
+#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
-static int set_lcktrmios(struct tty_struct * tty, struct termios * termios,
- int channel)
-{
- int i;
+ SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
+ SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
+ SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
+ SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
+ memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
- if (!suser())
- return -EPERM;
- for (i=0 ; i< (sizeof (*termios)) ; i++)
- ((char *)termios_locked[channel])[i] =
- get_fs_byte(i+(char *)termios);
+#undef SET_LOW_BITS
- return 0;
+ return set_termios_2(tty, &tmp_termios);
}
static int set_window_size(struct tty_struct * tty, struct winsize * ws)
{
- int i,changed;
- char c, * tmp;
+ struct winsize tmp_ws;
- if (!ws)
- return -EINVAL;
- tmp = (char *) &tty->winsize;
- changed = 0;
- for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
- c = get_fs_byte(i + (char *) ws);
- if (c == *tmp)
- continue;
- changed = 1;
- *tmp = c;
- }
- if (changed)
+ memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
+ if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
+ tty->pgrp > 0)
kill_pg(tty->pgrp, SIGWINCH, 1);
- return 0;
-}
-
-static int get_window_size(struct tty_struct * tty, struct winsize * ws)
-{
- int i;
- char * tmp;
-
- if (!ws)
- return -EINVAL;
- i = verify_area(VERIFY_WRITE, ws, sizeof (*ws));
- if (i)
- return i;
- tmp = (char *) ws;
- for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
- put_fs_byte(((char *) &tty->winsize)[i], tmp);
+ tty->winsize = tmp_ws;
return 0;
}
@@ -406,20 +324,19 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return 0;
}
-static int inq_canon(struct tty_struct * tty)
+static unsigned long inq_canon(struct tty_struct * tty)
{
int nr, head, tail;
- if (!tty->secondary.data)
+ if (!tty->canon_data)
return 0;
- head = tty->secondary.head;
+ head = tty->canon_head;
tail = tty->secondary.tail;
nr = (head - tail) & (TTY_BUF_SIZE-1);
/* Skip EOF-chars.. */
- if (EOF_CHAR(tty) == __DISABLED_CHAR)
- return nr;
while (head != tail) {
- if (tty->secondary.buf[tail] == EOF_CHAR(tty))
+ if (test_bit(tail, &tty->secondary_flags) &&
+ tty->secondary.buf[tail] == __DISABLED_CHAR)
nr--;
INC(tail);
}
@@ -432,7 +349,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
struct tty_struct * tty;
struct tty_struct * other_tty;
struct tty_struct * termios_tty;
- int pgrp;
+ pid_t pgrp;
int dev;
int termios_dev;
int retval;
@@ -449,68 +366,93 @@ int tty_ioctl(struct inode * inode, struct file * file,
other_tty = tty_table[PTY_OTHER(dev)];
else
other_tty = NULL;
- termios_tty = tty;
- termios_dev = dev;
if (IS_A_PTY_MASTER(dev)) {
termios_tty = other_tty;
termios_dev = PTY_OTHER(dev);
+ } else {
+ termios_tty = tty;
+ termios_dev = dev;
}
switch (cmd) {
case TCGETS:
- return get_termios(termios_tty,(struct termios *) arg);
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (struct termios));
+ if (retval)
+ return retval;
+ memcpy_tofs((struct termios *) arg,
+ termios_tty->termios,
+ sizeof (struct termios));
+ return 0;
case TCSETSF:
- flush_input(tty);
- /* fallthrough */
case TCSETSW:
- wait_until_sent(tty);
- /* fallthrough */
case TCSETS:
- return set_termios(termios_tty,(struct termios *) arg, termios_dev);
+ retval = check_change(termios_tty, termios_dev);
+ if (retval)
+ return retval;
+ if (cmd == TCSETSF || cmd == TCSETSW) {
+ if (cmd == TCSETSF)
+ flush_input(tty);
+ wait_until_sent(tty);
+ }
+ return set_termios(termios_tty, (struct termios *) arg,
+ termios_dev);
case TCGETA:
return get_termio(termios_tty,(struct termio *) arg);
case TCSETAF:
- flush_input(tty);
- /* fallthrough */
case TCSETAW:
- wait_until_sent(tty); /* fallthrough */
case TCSETA:
- return set_termio(termios_tty,(struct termio *) arg, termios_dev);
+ retval = check_change(termios_tty, termios_dev);
+ if (retval)
+ return retval;
+ if (cmd == TCSETAF || cmd == TCSETAW) {
+ if (cmd == TCSETAF)
+ flush_input(tty);
+ wait_until_sent(tty);
+ }
+ return set_termio(termios_tty, (struct termio *) arg,
+ termios_dev);
case TCXONC:
+ retval = check_change(tty, dev);
+ if (retval)
+ return retval;
switch (arg) {
case TCOOFF:
- tty->stopped = 1;
- if (tty->stop)
- (tty->stop)(tty);
- TTY_WRITE_FLUSH(tty);
- return 0;
+ stop_tty(tty);
+ break;
case TCOON:
- tty->stopped = 0;
- if (tty->start)
- (tty->start)(tty);
- TTY_WRITE_FLUSH(tty);
- return 0;
+ start_tty(tty);
+ break;
case TCIOFF:
- if (STOP_CHAR(tty))
+ if (STOP_CHAR(tty) != __DISABLED_CHAR)
put_tty_queue(STOP_CHAR(tty),
&tty->write_q);
- return 0;
+ break;
case TCION:
- if (START_CHAR(tty))
+ if (START_CHAR(tty) != __DISABLED_CHAR)
put_tty_queue(START_CHAR(tty),
&tty->write_q);
- return 0;
+ break;
+ default:
+ return -EINVAL;
}
- return -EINVAL; /* not implemented */
+ return 0;
case TCFLSH:
- if (arg==0)
+ retval = check_change(tty, dev);
+ if (retval)
+ return retval;
+ switch (arg) {
+ case TCIFLUSH:
flush_input(tty);
- else if (arg==1)
- flush_output(tty);
- else if (arg==2) {
+ break;
+ case TCIOFLUSH:
flush_input(tty);
+ /* fall through */
+ case TCOFLUSH:
flush_output(tty);
- } else
+ break;
+ default:
return -EINVAL;
+ }
return 0;
case TIOCEXCL:
set_bit(TTY_EXCLUSIVE, &tty->flags);
@@ -550,16 +492,21 @@ int tty_ioctl(struct inode * inode, struct file * file,
tty->pgrp = current->pgrp;
return 0;
case TIOCGPGRP:
- retval = verify_area(VERIFY_WRITE, (void *) arg,4);
- if (!retval)
- put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
- return retval;
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (pid_t));
+ if (retval)
+ return retval;
+ put_fs_long(termios_tty->pgrp, (pid_t *) arg);
+ return 0;
case TIOCSPGRP:
+ retval = check_change(tty, dev);
+ if (retval)
+ return retval;
if ((current->tty < 0) ||
(current->tty != termios_dev) ||
(termios_tty->session != current->session))
return -ENOTTY;
- pgrp=get_fs_long((unsigned long *) arg);
+ pgrp = get_fs_long((pid_t *) arg);
if (pgrp < 0)
return -EINVAL;
if (session_of_pgrp(pgrp) != current->session)
@@ -567,16 +514,19 @@ int tty_ioctl(struct inode * inode, struct file * file,
termios_tty->pgrp = pgrp;
return 0;
case TIOCOUTQ:
- retval = verify_area(VERIFY_WRITE, (void *) arg,4);
- if (!retval)
- put_fs_long(CHARS(&tty->write_q),
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (unsigned long));
+ if (retval)
+ return retval;
+ put_fs_long(CHARS(&tty->write_q),
(unsigned long *) arg);
- return retval;
+ return 0;
case TIOCINQ:
- retval = verify_area(VERIFY_WRITE, (void *) arg,4);
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (unsigned long));
if (retval)
return retval;
- if (L_CANON(tty))
+ if (L_ICANON(tty))
put_fs_long(inq_canon(tty),
(unsigned long *) arg);
else
@@ -587,17 +537,20 @@ int tty_ioctl(struct inode * inode, struct file * file,
if ((current->tty != dev) && !suser())
return -EACCES;
put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
+ TTY_READ_FLUSH(tty);
return 0;
case TIOCGWINSZ:
- return get_window_size(tty,(struct winsize *) arg);
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (struct winsize));
+ if (retval)
+ return retval;
+ memcpy_tofs((struct winsize *) arg, &tty->winsize,
+ sizeof (struct winsize));
+ return 0;
case TIOCSWINSZ:
if (IS_A_PTY_MASTER(dev))
set_window_size(other_tty,(struct winsize *) arg);
return set_window_size(tty,(struct winsize *) arg);
- case TIOCGSOFTCAR:
- return -EINVAL; /* not implemented */
- case TIOCSSOFTCAR:
- return -EINVAL; /* not implemented */
case TIOCLINUX:
switch (get_fs_byte((char *)arg))
{
@@ -647,31 +600,55 @@ int tty_ioctl(struct inode * inode, struct file * file,
current->tty = -1;
return 0;
case TIOCGETD:
- retval = verify_area(VERIFY_WRITE, (void *) arg,4);
- if (!retval)
- put_fs_long(tty->disc, (unsigned long *) arg);
- return retval;
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (unsigned long));
+ if (retval)
+ return retval;
+ put_fs_long(tty->disc, (unsigned long *) arg);
+ return 0;
case TIOCSETD:
+ retval = check_change(tty, dev);
+ if (retval)
+ return retval;
arg = get_fs_long((unsigned long *) arg);
return tty_set_ldisc(tty, arg);
case TIOCGLCKTRMIOS:
arg = get_fs_long((unsigned long *) arg);
- return get_lcktrmios(tty, (struct termios *) arg,
- termios_dev);
+ retval = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof (struct termios));
+ if (retval)
+ return retval;
+ memcpy_tofs((struct termios *) arg,
+ &termios_locked[termios_dev],
+ sizeof (struct termios));
+ return 0;
case TIOCSLCKTRMIOS:
+ if (!suser())
+ return -EPERM;
arg = get_fs_long((unsigned long *) arg);
- return set_lcktrmios(tty, (struct termios *) arg,
- termios_dev);
+ memcpy_fromfs(&termios_locked[termios_dev],
+ (struct termios *) arg,
+ sizeof (struct termios));
+ return 0;
case TIOCPKT:
if (!IS_A_PTY_MASTER(dev))
return -EINVAL;
- retval = verify_area(VERIFY_READ,
- (unsigned long *)arg, sizeof (unsigned long));
+ retval = verify_area(VERIFY_READ, (void *) arg,
+ sizeof (unsigned long));
if (retval)
return retval;
- tty->packet = (get_fs_long ((unsigned long *)arg) != 0);
+ if (get_fs_long(arg)) {
+ if (!tty->packet) {
+ tty->packet = 1;
+ tty->ctrl_status = 0;
+ }
+ } else
+ tty->packet = 0;
return 0;
case TCSBRK: case TCSBRKP:
+ retval = check_change(tty, dev);
+ if (retval)
+ return retval;
wait_until_sent(tty);
if (!tty->ioctl)
return 0;
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index f4f5641..e6759ea 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -36,7 +36,6 @@ static char *version =
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
-#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 4e9642b..d6c77ed 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -563,8 +563,12 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
if (skb->free)
kfree_skb (skb, FREE_WRITE);
} else
+ {
+ /* Gimme!!! */
+ if(skb->free==0)
+ skb_kept_by_device(skb);
lp->tx_ring[entry].base = (int)(skb+1) | 0x83000000;
-
+ }
lp->cur_tx++;
/* Trigger an immediate send poll. */
@@ -648,6 +652,9 @@ lance_interrupt(int reg_ptr)
struct sk_buff *skb = ((struct sk_buff *)databuff) - 1;
if (skb->free)
kfree_skb(skb, FREE_WRITE);
+ else
+ skb_device_release(skb,FREE_WRITE);
+ /* Warning: skb may well vanish at the point you call device_release! */
}
dirty_tx++;
}
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 2f3ea0d..fb722fd 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -31,13 +31,11 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
-#include <linux/termios.h>
#include <linux/sockios.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/stat.h>
-#include <linux/tty.h>
#include <linux/in.h>
#include "inet.h"
#include "dev.h"
diff --git a/fs/open.c b/fs/open.c
index 1871392..b7dc800 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -262,6 +262,8 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
+ if (mode == (mode_t) -1)
+ mode = inode->i_mode;
inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
if (!suser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
@@ -286,6 +288,8 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
iput(inode);
return -EROFS;
}
+ if (mode == (mode_t) -1)
+ mode = inode->i_mode;
inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
if (!suser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 1da619d..665e42f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -14,11 +14,6 @@
#define LONG_MAX ((long)(~0UL>>1))
#define ULONG_MAX (~0UL)
-#define VERIFY_READ 0
-#define VERIFY_WRITE 1
-
-int verify_area(int type, void * addr, unsigned long count);
-
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 89e7fe2..d890096 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,9 +2,26 @@
#define _LINUX_MM_H
#include <linux/page.h>
-#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
#include <linux/kernel.h>
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+int __verify_write(unsigned long addr, unsigned long count);
+
+extern inline int verify_area(int type, void * addr, unsigned long size)
+{
+ if (TASK_SIZE <= (unsigned long) addr)
+ return -EFAULT;
+ if (size > TASK_SIZE - (unsigned long) addr)
+ return -EFAULT;
+ if (wp_works_ok || type == VERIFY_READ || !size)
+ return 0;
+ return __verify_write((unsigned long) addr,size);
+}
+
/*
* Linux kernel virtual memory manager primitives.
* The idea being to have a "virtual" mm in the same way
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9a335a0..6ee77bf 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -13,6 +13,21 @@
#define HZ 100
+/*
+ * System setup flags..
+ */
+extern int hard_math;
+extern int x86;
+extern int ignore_irq13;
+extern int wp_works_ok;
+
+/*
+ * Bus types (default is ISA, but people can check others with these..)
+ * MCA_bus hardcoded to 0 for now.
+ */
+extern int EISA_bus;
+#define MCA_bus 0
+
#include <linux/tasks.h>
#include <asm/system.h>
@@ -290,21 +305,6 @@ extern unsigned long volatile jiffies;
extern struct timeval xtime;
extern int need_resched;
-/*
- * System setup flags..
- */
-extern int hard_math;
-extern int x86;
-extern int ignore_irq13;
-extern int wp_works_ok;
-
-/*
- * Bus types (default is ISA, but people can check others with these..)
- * MCA_bus hardcoded to 0 for now.
- */
-extern int EISA_bus;
-#define MCA_bus 0
-
#define CURRENT_TIME (xtime.tv_sec)
extern void sleep_on(struct wait_queue ** p);
diff --git a/include/linux/termios.h b/include/linux/termios.h
index 85948ec..a2528bd 100644
--- a/include/linux/termios.h
+++ b/include/linux/termios.h
@@ -51,6 +51,7 @@
#define TIOCSLCKTRMIOS 0x5457
/* Used for packet mode */
+#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
#define TIOCPKT_FLUSHWRITE 2
#define TIOCPKT_STOP 4
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 12530e7..732bd4e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -62,7 +62,6 @@ extern struct screen_info screen_info;
#define TTY_BUF_SIZE 1024 /* Must be a power of 2 */
struct tty_queue {
- unsigned long data;
unsigned long head;
unsigned long tail;
struct wait_queue * proc_list;
@@ -143,60 +142,88 @@ struct serial_struct {
#define FULL(a) (!LEFT(a))
#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1))
-extern void put_tty_queue(char c, struct tty_queue * queue);
+extern void put_tty_queue(unsigned char c, struct tty_queue * queue);
extern int get_tty_queue(struct tty_queue * queue);
#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
-#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
+#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
+#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
+#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
-#define SUSPEND_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
+#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
+#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
+#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
+#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
+#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT])
+#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
-#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & f)
-#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & f)
-#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & f)
-#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & f)
-
-#define L_CANON(tty) _L_FLAG((tty),ICANON)
-#define L_ISIG(tty) _L_FLAG((tty),ISIG)
-#define L_ECHO(tty) _L_FLAG((tty),ECHO)
-#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
-#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
-#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
-#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
-#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
-#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
+#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f))
+#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f))
+#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f))
+#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f))
#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
#define I_INPCK(tty) _I_FLAG((tty),INPCK)
-#define I_UCLC(tty) _I_FLAG((tty),IUCLC)
-#define I_NLCR(tty) _I_FLAG((tty),INLCR)
-#define I_CRNL(tty) _I_FLAG((tty),ICRNL)
-#define I_NOCR(tty) _I_FLAG((tty),IGNCR)
+#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
+#define I_INLCR(tty) _I_FLAG((tty),INLCR)
+#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
+#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
+#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
#define I_IXON(tty) _I_FLAG((tty),IXON)
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
-#define I_STRP(tty) _I_FLAG((tty),ISTRIP)
-
-#define O_POST(tty) _O_FLAG((tty),OPOST)
-#define O_LCUC(tty) _O_FLAG((tty),OLCUC)
-#define O_NLCR(tty) _O_FLAG((tty),ONLCR)
-#define O_CRNL(tty) _O_FLAG((tty),OCRNL)
-#define O_NOCR(tty) _O_FLAG((tty),ONOCR)
-#define O_NLRET(tty) _O_FLAG((tty),ONLRET)
+#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
+#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
+
+#define O_OPOST(tty) _O_FLAG((tty),OPOST)
+#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
+#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
+#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
+#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
+#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
+#define O_OFILL(tty) _O_FLAG((tty),OFILL)
+#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
+#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
+#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
+#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
+#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
+#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
+
+#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
+#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
+#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
+#define C_CREAD(tty) _C_FLAG((tty),CREAD)
+#define C_PARENB(tty) _C_FLAG((tty),PARENB)
+#define C_PARODD(tty) _C_FLAG((tty),PARODD)
+#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
+#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
+#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
+#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
-#define C_LOCAL(tty) _C_FLAG((tty),CLOCAL)
-#define C_RTSCTS(tty) _C_FLAG((tty),CRTSCTS)
-#define C_SPEED(tty) ((tty)->termios->c_cflag & CBAUD)
-#define C_HUP(tty) (C_SPEED((tty)) == B0)
+#define L_ISIG(tty) _L_FLAG((tty),ISIG)
+#define L_ICANON(tty) _L_FLAG((tty),ICANON)
+#define L_XCASE(tty) _L_FLAG((tty),XCASE)
+#define L_ECHO(tty) _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
+#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
+#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
+#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
+#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
+#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
+#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
+#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
+#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
/*
* Where all of the state associated with a tty is kept while the tty
@@ -218,12 +245,13 @@ struct tty_struct {
int session;
unsigned char stopped:1, hw_stopped:1, packet:1, lnext:1;
unsigned char char_error:3;
+ unsigned char erasing:1;
unsigned char ctrl_status;
short line;
int disc;
int flags;
int count;
- int column;
+ unsigned int column;
struct winsize winsize;
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
@@ -241,10 +269,13 @@ struct tty_struct {
void (*write_data_callback)(void * data);
void * write_data_arg;
int readq_flags[TTY_BUF_SIZE/32];
+ int secondary_flags[TTY_BUF_SIZE/32];
+ int canon_data;
+ unsigned long canon_head;
+ unsigned int canon_column;
struct tty_queue read_q;
struct tty_queue write_q;
struct tty_queue secondary;
- struct wait_queue * except_q;
void *disc_data;
};
@@ -256,9 +287,9 @@ struct tty_ldisc {
int (*open)(struct tty_struct *);
void (*close)(struct tty_struct *);
int (*read)(struct tty_struct * tty, struct file * file,
- char * buf, int nr);
+ unsigned char * buf, unsigned int nr);
int (*write)(struct tty_struct * tty, struct file * file,
- char * buf, int nr);
+ unsigned char * buf, unsigned int nr);
int (*ioctl)(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
int (*select)(struct tty_struct * tty, struct inode * inode,
@@ -313,12 +344,11 @@ struct tty_ldisc {
*/
#define TTY_WRITE_BUSY 0
#define TTY_READ_BUSY 1
-#define TTY_CR_PENDING 2
-#define TTY_SQ_THROTTLED 3
-#define TTY_RQ_THROTTLED 4
-#define TTY_IO_ERROR 5
-#define TTY_SLAVE_OPENED 6
-#define TTY_EXCLUSIVE 7
+#define TTY_SQ_THROTTLED 2
+#define TTY_RQ_THROTTLED 3
+#define TTY_IO_ERROR 4
+#define TTY_SLAVE_CLOSED 5
+#define TTY_EXCLUSIVE 6
/*
* When a break, frame error, or parity error happens, these codes are
@@ -336,6 +366,10 @@ struct tty_ldisc {
extern void tty_write_flush(struct tty_struct *);
extern void tty_read_flush(struct tty_struct *);
+/* Number of chars that must be available in a write queue before
+ the queue is awakened. */
+#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
+
extern struct tty_struct *tty_table[];
extern struct termios *tty_termios[];
extern struct termios *termios_locked[];
@@ -366,7 +400,9 @@ extern long tty_init(long);
extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty);
extern void wait_until_sent(struct tty_struct * tty);
-extern void copy_to_cooked(struct tty_struct * tty);
+extern int check_change(struct tty_struct * tty, int channel);
+extern void stop_tty(struct tty_struct * tty);
+extern void start_tty(struct tty_struct * tty);
extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
diff --git a/kernel/fork.c b/kernel/fork.c
index 48589f5..306ddab 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -56,7 +56,8 @@ repeat:
}
if (task[i]->uid == current->uid)
this_user_tasks++;
- if (task[i]->pid == last_pid || task[i]->pgrp == last_pid)
+ if (task[i]->pid == last_pid || task[i]->pgrp == last_pid ||
+ task[i]->session == last_pid)
goto repeat;
}
if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT ||
diff --git a/kernel/ksyms.S b/kernel/ksyms.S
index d30cbed..acb4752 100644
--- a/kernel/ksyms.S
+++ b/kernel/ksyms.S
@@ -9,7 +9,7 @@
_register_chrdev
_unregister_chrdev
-_verify_area
+___verify_write
_wake_up_interruptible
_current
diff --git a/kernel/sys.c b/kernel/sys.c
index 1327564..a158393 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -7,7 +7,6 @@
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
-#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/times.h>
#include <linux/utsname.h>
@@ -510,7 +509,7 @@ asmlinkage int sys_getpgrp(void)
asmlinkage int sys_setsid(void)
{
- if (current->leader && !suser())
+ if (current->leader)
return -EPERM;
current->leader = 1;
current->session = current->pgrp = current->pid;
diff --git a/mm/memory.c b/mm/memory.c
index 3c2e49e..57cee25 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -651,17 +651,8 @@ void do_wp_page(unsigned long error_code, unsigned long address,
*pg_table = 0;
}
-int verify_area(int type, void * addr, unsigned long size)
+int __verify_write(unsigned long start, unsigned long size)
{
- unsigned long start;
-
- start = (unsigned long) addr;
- if (start >= TASK_SIZE)
- return -EFAULT;
- if (size > TASK_SIZE - start)
- return -EFAULT;
- if (wp_works_ok || type == VERIFY_READ || !size)
- return 0;
size--;
size += start & ~PAGE_MASK;
size >>= PAGE_SHIFT;
diff --git a/net/inet/ip.c b/net/inet/ip.c
index 4cd04a4..af6fdbf 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -1464,7 +1464,8 @@ ip_retransmit(struct sock *sk, int all)
/* If the interface is (still) up and running, kick it. */
if (dev->flags & IFF_UP) {
- if (sk) dev->queue_xmit(skb, dev, sk->priority);
+ if (sk && !skb_device_locked(skb))
+ dev->queue_xmit(skb, dev, sk->priority);
/* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c
index 2898729..506e95d 100644
--- a/net/inet/skbuff.c
+++ b/net/inet/skbuff.c
@@ -381,6 +381,12 @@ void kfree_skb(struct sk_buff *skb, int rw)
return;
}
IS_SKB(skb);
+ if(skb->lock)
+ {
+ skb->free=1; /* Free when unlocked */
+ return;
+ }
+
if(skb->free == 2)
printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
if(skb->list)
@@ -424,6 +430,7 @@ void kfree_skb(struct sk_buff *skb, int rw)
return NULL;
skb->free= 2; /* Invalid so we pick up forgetful users */
skb->list= 0; /* Not on a list */
+ skb->lock= 0;
skb->truesize=size;
skb->mem_len=size;
skb->mem_addr=skb;
@@ -452,3 +459,31 @@ void kfree_skbmem(void *mem,unsigned size)
}
}
+/*
+ * Skbuff device locking
+ */
+
+void skb_kept_by_device(struct sk_buff *skb)
+{
+ skb->lock++;
+}
+
+void skb_device_release(struct sk_buff *skb, int mode)
+{
+ unsigned long flags;
+ save_flags(flags);
+ skb->lock--;
+ if(skb->lock==0)
+ {
+ if(skb->free==1)
+ kfree_skb(skb,mode);
+ }
+ restore_flags(flags);
+}
+
+int skb_device_locked(struct sk_buff *skb)
+{
+ if(skb->lock)
+ return 1;
+ return 0;
+}
diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h
index fb7595a..e976385 100644
--- a/net/inet/skbuff.h
+++ b/net/inet/skbuff.h
@@ -99,7 +99,9 @@ extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
extern struct sk_buff * alloc_skb(unsigned int size, int priority);
extern void kfree_skbmem(void *mem, unsigned size);
-
+extern void skb_kept_by_device(struct sk_buff *skb);
+extern void skb_device_release(struct sk_buff *skb, int mode);
+extern int skb_device_locked(struct sk_buff *skb);
extern void skb_check(struct sk_buff *skb,int, char *);
#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index a3375d4..4de3e1e 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -583,64 +583,41 @@ tcp_check(struct tcphdr *th, int len,
}
-void
-tcp_send_check(struct tcphdr *th, unsigned long saddr,
- unsigned long daddr, int len, struct sock *sk)
-{
- th->check = 0;
- th->check = tcp_check(th, len, saddr, daddr);
- return;
-}
-
-static struct sk_buff * dequeue_partial(struct sock * sk)
+void tcp_send_check(struct tcphdr *th, unsigned long saddr,
+ unsigned long daddr, int len, struct sock *sk)
{
- struct sk_buff * skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb = sk->send_tmp;
- if (skb) {
- sk->send_tmp = skb->next;
- skb->next = NULL;
- }
- restore_flags(flags);
- return skb;
+ th->check = 0;
+ th->check = tcp_check(th, len, saddr, daddr);
+ return;
}
-static void enqueue_partial(struct sk_buff * skb, struct sock * sk)
+static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
{
- unsigned long flags;
+ int size;
- save_flags(flags);
- cli();
- skb->next = sk->send_tmp;
- sk->send_tmp = skb;
- restore_flags(flags);
-}
+ /* length of packet (not counting length of pre-tcp headers) */
+ size = skb->len - ((unsigned char *) skb->h.th - skb->data);
-static void tcp_send_partial(struct sock *sk)
-{
- struct sk_buff *skb;
+ /* sanity check it.. */
+ if (size < sizeof(struct tcphdr) || size > skb->len) {
+ printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
+ skb, skb->data, skb->h.th, skb->len);
+ kfree_skb(skb, FREE_WRITE);
+ return;
+ }
- if (sk == NULL)
- return;
- while ((skb = dequeue_partial(sk)) != NULL) {
-
/* If we have queued a header size packet.. */
- if(skb->len-(unsigned long)skb->h.th + (unsigned long)skb->data == sizeof(struct tcphdr)) {
+ if (size == sizeof(struct tcphdr)) {
/* If its got a syn or fin its notionally included in the size..*/
if(!skb->h.th->syn && !skb->h.th->fin) {
- printk("tcp_send_partial: attempt to queue a bogon.\n");
+ printk("tcp_send_skb: attempt to queue a bogon.\n");
kfree_skb(skb,FREE_WRITE);
return;
}
}
/* We need to complete and send the packet. */
- tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
- skb->len-(unsigned long)skb->h.th +
- (unsigned long)skb->data, sk);
+ tcp_send_check(skb->h.th, sk->saddr, sk->daddr, size, sk);
skb->h.seq = sk->send_seq;
if (after(sk->send_seq , sk->window_seq) ||
@@ -664,9 +641,49 @@ static void tcp_send_partial(struct sock *sk)
reset_timer(sk, TIME_PROBE0,
backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
} else {
- sk->prot->queue_xmit(sk, skb->dev, skb,0);
+ sk->prot->queue_xmit(sk, skb->dev, skb, 0);
}
- }
+}
+
+static struct sk_buff * dequeue_partial(struct sock * sk)
+{
+ struct sk_buff * skb;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ skb = sk->send_tmp;
+ if (skb) {
+ sk->send_tmp = skb->next;
+ skb->next = NULL;
+ }
+ restore_flags(flags);
+ return skb;
+}
+
+static void enqueue_partial(struct sk_buff * skb, struct sock * sk)
+{
+ struct sk_buff * tmp;
+ unsigned long flags;
+
+ skb->next = NULL;
+ save_flags(flags);
+ cli();
+ tmp = sk->send_tmp;
+ sk->send_tmp = skb;
+ restore_flags(flags);
+ if (tmp)
+ tcp_send_skb(sk, tmp);
+}
+
+static void tcp_send_partial(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ if (sk == NULL)
+ return;
+ while ((skb = dequeue_partial(sk)) != NULL)
+ tcp_send_skb(sk, skb);
}
@@ -901,6 +918,7 @@ tcp_write(struct sock *sk, unsigned char *from,
continue;
}
+#if 0
/*
* We also need to worry about the window.
* If window < 1/4 offered window, don't use it. That's
@@ -915,6 +933,10 @@ tcp_write(struct sock *sk, unsigned char *from,
copy = sk->mtu;
copy = min(copy, sk->mtu);
copy = min(copy, len);
+#else
+ /* This also prevents silly windows by simply ignoring the offered window.. */
+ copy = min(sk->mtu, len);
+#endif
/* We should really check the window here also. */
if (sk->packets_out && copy < sk->mtu && !(flags & MSG_OOB)) {
@@ -1011,34 +1033,7 @@ tcp_write(struct sock *sk, unsigned char *from,
enqueue_partial(send_tmp, sk);
continue;
}
-
- tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr,
- copy + sizeof(struct tcphdr), sk);
-
- skb->h.seq = sk->send_seq;
- if (after(sk->send_seq , sk->window_seq) ||
- (sk->retransmits && sk->timeout == TIME_WRITE) ||
- sk->packets_out >= sk->cong_window) {
- DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
- sk->cong_window, sk->packets_out));
- DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
- sk->send_seq, sk->window_seq));
- skb->next = NULL;
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (sk->wback == NULL) {
- sk->wfront = skb;
- } else {
- sk->wback->next = skb;
- }
- sk->wback = skb;
- if (before(sk->window_seq, sk->wfront->h.seq) &&
- sk->send_head == NULL &&
- sk->ack_backlog == 0)
- reset_timer(sk, TIME_PROBE0,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
- } else {
- prot->queue_xmit(sk, dev, skb,0);
- }
+ tcp_send_skb(sk, skb);
}
sk->err = 0;
@@ -3604,7 +3599,7 @@ tcp_send_probe0(struct sock *sk)
len = hlen + sizeof(struct tcphdr) + (data ? 1 : 0);
/* Allocate buffer. */
- if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len,GFP_KERNEL)) == NULL) {
+ if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len, GFP_ATOMIC)) == NULL) {
/* printk("alloc failed raw %x th %x hlen %d data %d len %d\n",
raw, skb->h.th, hlen, data, len); */
reset_timer (sk, TIME_PROBE0, 10); /* try again real soon */
diff --git a/net/socket.c b/net/socket.c
index e679128..6caa65b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -28,7 +28,6 @@
#include <linux/stat.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
-#include <linux/termios.h>
#include <linux/net.h>
#include <linux/ddi.h>