2006-01-19 00:01:34

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 0/8] Other UML batch

Various little UML fixups. The only non-trivial one is "uml: fix hugest stack
users", which avoids C99 initializers for huge (6k) structs (due to the "copy
them twice on the stack" gcc niceness).

--
Inform me of my mistakes, so I can keep imitating Homer Simpson's "Doh!".
Paolo Giarrusso, aka Blaisorblade (Skype ID "PaoloGiarrusso", ICQ 215621894)
http://www.user-mode-linux.org/~blaisorblade


2006-01-18 23:59:59

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 7/8] uml: some harmless sparse warning fixes


Fix some simple sparse warnings - a lot more staticness and a misplaced __user.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

arch/um/drivers/chan_kern.c | 6 +++---
arch/um/drivers/daemon_kern.c | 4 ++--
arch/um/drivers/line.c | 2 +-
arch/um/drivers/mcast_kern.c | 2 +-
arch/um/drivers/mconsole_kern.c | 9 ++++++---
arch/um/drivers/ssl.c | 6 +++---
arch/um/kernel/exec_kern.c | 2 +-
7 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index ab0d0b1..7218c75 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -403,7 +403,7 @@ int chan_window_size(struct list_head *c
return 0;
}

-void free_one_chan(struct chan *chan, int delay_free_irq)
+static void free_one_chan(struct chan *chan, int delay_free_irq)
{
list_del(&chan->list);

@@ -416,7 +416,7 @@ void free_one_chan(struct chan *chan, in
kfree(chan);
}

-void free_chan(struct list_head *chans, int delay_free_irq)
+static void free_chan(struct list_head *chans, int delay_free_irq)
{
struct list_head *ele, *next;
struct chan *chan;
@@ -497,7 +497,7 @@ struct chan_type {
struct chan_ops *ops;
};

-struct chan_type chan_table[] = {
+static struct chan_type chan_table[] = {
{ "fd", &fd_ops },

#ifdef CONFIG_NULL_CHAN
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index 507e3cb..a61b7b4 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -18,7 +18,7 @@ struct daemon_init {
char *ctl_sock;
};

-void daemon_init(struct net_device *dev, void *data)
+static void daemon_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct daemon_data *dpri;
@@ -64,7 +64,7 @@ static struct net_kern_info daemon_kern_
.write = daemon_write,
};

-int daemon_setup(char *str, char **mac_out, void *data)
+static int daemon_setup(char *str, char **mac_out, void *data)
{
struct daemon_init *init = data;
char *remain;
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 46ceb25..6c2d4cc 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -714,7 +714,7 @@ struct winch {
struct tty_struct *tty;
};

-irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
{
struct winch *winch = data;
struct tty_struct *tty;
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index 217438c..e80fdda 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -26,7 +26,7 @@ struct mcast_init {
int ttl;
};

-void mcast_init(struct net_device *dev, void *data)
+static void mcast_init(struct net_device *dev, void *data)
{
struct uml_net_private *pri;
struct mcast_data *dpri;
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index e3d5765..e87ecf0 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -327,7 +327,7 @@ void mconsole_stop(struct mc_request *re

/* This list is populated by __initcall routines. */

-LIST_HEAD(mconsole_devices);
+static LIST_HEAD(mconsole_devices);

void mconsole_register_dev(struct mc_device *new)
{
@@ -561,6 +561,8 @@ void mconsole_sysrq(struct mc_request *r
}
#endif

+#ifdef CONFIG_MODE_SKAS
+
static void stack_proc(void *arg)
{
struct task_struct *from = current, *to = arg;
@@ -574,7 +576,7 @@ static void stack_proc(void *arg)
* Dumps a stacks registers to the linux console.
* Usage stack <pid>.
*/
-void do_stack(struct mc_request *req)
+static void do_stack_trace(struct mc_request *req)
{
char *ptr = req->request.data;
int pid_requested= -1;
@@ -605,6 +607,7 @@ void do_stack(struct mc_request *req)
}
with_console(req, stack_proc, to);
}
+#endif /* CONFIG_MODE_SKAS */

void mconsole_stack(struct mc_request *req)
{
@@ -613,7 +616,7 @@ void mconsole_stack(struct mc_request *r
*/
CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
1, 0),
- do_stack(req));
+ do_stack_trace(req));
}

/* Changed by mconsole_setup, which is __setup, and called before SMP is
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index a32ef55..a4d6415 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -33,7 +33,7 @@ static struct tty_driver *ssl_driver;

#define NR_PORTS 64

-void ssl_announce(char *dev_name, int dev)
+static void ssl_announce(char *dev_name, int dev)
{
printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
dev_name);
@@ -98,7 +98,7 @@ static int ssl_remove(int n)
return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n);
}

-int ssl_open(struct tty_struct *tty, struct file *filp)
+static int ssl_open(struct tty_struct *tty, struct file *filp)
{
return line_open(serial_lines, tty);
}
@@ -182,7 +182,7 @@ static struct console ssl_cons = {
.index = -1,
};

-int ssl_init(void)
+static int ssl_init(void)
{
char *new_title;

diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
index efd222f..e751e29 100644
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -34,7 +34,7 @@ void start_thread(struct pt_regs *regs,
extern void log_exec(char **argv, void *tty);

static long execve1(char *file, char __user * __user *argv,
- char *__user __user *env)
+ char __user *__user *env)
{
long error;


2006-01-18 23:59:37

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 3/8] uml: fix hugest stack users


The C99 initialization, with GCC's bad handling, for 6K wide structs (which
_aren't_ on the stack), is causing GCC to use 12K for these silly procs with 3
vars. Workaround this.

Note that .name = { '\0' } translates to memset(->name, 0, '->name' size) - I verified
this with GCC's docs and a testprogram.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

arch/um/drivers/slip_common.h | 13 +++++++------
arch/um/drivers/slip_kern.c | 15 ++++++++-------
arch/um/drivers/slirp_kern.c | 13 +++++++------
3 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/arch/um/drivers/slip_common.h b/arch/um/drivers/slip_common.h
index 2ae76d8..d574e0a 100644
--- a/arch/um/drivers/slip_common.h
+++ b/arch/um/drivers/slip_common.h
@@ -88,12 +88,13 @@ struct slip_proto {
int esc;
};

-#define SLIP_PROTO_INIT { \
- .ibuf = { '\0' }, \
- .obuf = { '\0' }, \
- .more = 0, \
- .pos = 0, \
- .esc = 0 \
+static inline void slip_proto_init(struct slip_proto * slip)
+{
+ memset(slip->ibuf, 0, sizeof(slip->ibuf));
+ memset(slip->obuf, 0, sizeof(slip->obuf));
+ slip->more = 0;
+ slip->pos = 0;
+ slip->esc = 0;
}

extern int slip_proto_read(int fd, void *buf, int len,
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index 9a6f5c8..a62f5ef 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -21,13 +21,14 @@ void slip_init(struct net_device *dev, v

private = dev->priv;
spri = (struct slip_data *) private->user;
- *spri = ((struct slip_data)
- { .name = { '\0' },
- .addr = NULL,
- .gate_addr = init->gate_addr,
- .slave = -1,
- .slip = SLIP_PROTO_INIT,
- .dev = dev });
+
+ memset(spri->name, 0, sizeof(spri->name));
+ spri->addr = NULL;
+ spri->gate_addr = init->gate_addr;
+ spri->slave = -1;
+ spri->dev = dev;
+
+ slip_proto_init(&spri->slip);

dev->init = NULL;
dev->header_cache_update = NULL;
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
index 9864d27..33d7982 100644
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -21,12 +21,13 @@ void slirp_init(struct net_device *dev,

private = dev->priv;
spri = (struct slirp_data *) private->user;
- *spri = ((struct slirp_data)
- { .argw = init->argw,
- .pid = -1,
- .slave = -1,
- .slip = SLIP_PROTO_INIT,
- .dev = dev });
+
+ spri->argw = init->argw;
+ spri->pid = -1;
+ spri->slave = -1;
+ spri->dev = dev;
+
+ slip_proto_init(&spri->slip);

dev->init = NULL;
dev->hard_header_len = 0;

2006-01-18 23:59:37

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 2/8] uml: comments about libc-conflict guards


While fixing myself the mktime conflict (which someone already merged), I also
improved a few comments. Merge them up.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

arch/um/Makefile | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/um/Makefile b/arch/um/Makefile
index 45435ff..936fd72 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -47,13 +47,16 @@ ARCH_INCLUDE += -I$(srctree)/$(ARCH_DIR)
endif
SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH)

-# -Dvmap=kernel_vmap affects everything, and prevents anything from
-# referencing the libpcap.o symbol so named.
+# -Dvmap=kernel_vmap prevents anything from referencing the libpcap.o symbol so
+# named - it's a common symbol in libpcap, so we get a binary which crashes.
#
-# Same things for in6addr_loopback - found in libc.
+# Same things for in6addr_loopback and mktime - found in libc. For these two we
+# only get link-time error, luckily.
+#
+# These apply to USER_CFLAGS to.

-CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
- $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
+CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+ $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \
-Din6addr_loopback=kernel_in6addr_loopback

AFLAGS += $(ARCH_INCLUDE)
@@ -66,6 +69,7 @@ USER_CFLAGS := $(patsubst -D__KERNEL__,,
# kernel_errno to separate them from the libc errno. This allows -fno-common
# in CFLAGS. Otherwise, it would cause ld to complain about the two different
# errnos.
+# These apply to kernelspace only.

CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
-Dmktime=kernel_mktime

2006-01-19 00:00:00

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 6/8] uml: skas0-hold-own-ldt fixups for x86-64


In a recent fixup i386 code was copied raw to x86_64 subarch to make it compile
again.

Here there are some little fixups and resyncs needed for it (mainly for
cleanliness sake) - I did an audit and found the rest of the code to be safe.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

include/asm-um/ldt-x86_64.h | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/include/asm-um/ldt-x86_64.h b/include/asm-um/ldt-x86_64.h
index 57159f1..96b35aa 100644
--- a/include/asm-um/ldt-x86_64.h
+++ b/include/asm-um/ldt-x86_64.h
@@ -39,11 +39,13 @@ typedef struct uml_ldt {
} uml_ldt_t;

/*
- * macros stolen from include/asm-i386/desc.h
+ * macros stolen from include/asm-x86_64/desc.h
*/
#define LDT_entry_a(info) \
((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))

+/* Don't allow setting of the lm bit. It is useless anyways because
+ * 64bit system calls require __USER_CS. */
#define LDT_entry_b(info) \
(((info)->base_addr & 0xff000000) | \
(((info)->base_addr & 0x00ff0000) >> 16) | \
@@ -54,6 +56,7 @@ typedef struct uml_ldt {
((info)->seg_32bit << 22) | \
((info)->limit_in_pages << 23) | \
((info)->useable << 20) | \
+ /* ((info)->lm << 21) | */ \
0x7000)

#define LDT_empty(info) (\
@@ -64,6 +67,7 @@ typedef struct uml_ldt {
(info)->seg_32bit == 0 && \
(info)->limit_in_pages == 0 && \
(info)->seg_not_present == 1 && \
- (info)->useable == 0 )
+ (info)->useable == 0 && \
+ (info)->lm == 0)

#endif

2006-01-19 00:00:51

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 5/8] uml: TT - SYSCALL_DEBUG - fix buglet introduced in cleanup


Fixes a bug introduced in commit e32dacb9f481fd6decb41adb28e720c923d34f54 -
index is initialized based on syscall before syscall is calculated.

I'm bothering with this mainly because it gives a correct warning when the config
option is enabled, even if the code is for a almost unused debugging option.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

arch/um/kernel/tt/syscall_kern.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
index 3d29c90..3fda9a0 100644
--- a/arch/um/kernel/tt/syscall_kern.c
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -23,16 +23,20 @@ void syscall_handler_tt(int sig, struct
int syscall;
#ifdef CONFIG_SYSCALL_DEBUG
int index;
- index = record_syscall_start(syscall);
#endif
sc = UPT_SC(&regs->regs);
SC_START_SYSCALL(sc);

+ syscall = UPT_SYSCALL_NR(&regs->regs);
+
+#ifdef CONFIG_SYSCALL_DEBUG
+ index = record_syscall_start(syscall);
+#endif
+
syscall_trace(&regs->regs, 0);

current->thread.nsyscalls++;
nsyscalls++;
- syscall = UPT_SYSCALL_NR(&regs->regs);

if((syscall >= NR_syscalls) || (syscall < 0))
result = -ENOSYS;

2006-01-19 00:00:51

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 8/8] uml: avoid "CONFIG_NR_CPUS undeclared" bogus error messages


From: Paolo 'Blaisorblade' Giarrusso <[email protected]>, Olaf Hering <[email protected]>

Olaf reported UML doesn't build for him with a clear analisys of what happened -
we're using NR_CPUS in files linked against glibc headers. Seems like it defines
CONFIG_SMP but not CONFIG_NR_CPUS, so we get CONFIG_NR_CPUS undeclared.

The fix is to move the declaration away from that header file and move it in
asm-um headers, and to add that header where needed.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

arch/um/include/kern_util.h | 2 --
arch/um/kernel/reboot.c | 1 +
include/asm-um/smp.h | 2 ++
3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index c649108..07176d9 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -31,8 +31,6 @@ extern int timer_irq_inited;
extern int jail;
extern int nsyscalls;

-extern struct task_struct *idle_threads[NR_CPUS];
-
#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
#define UML_ROUND_UP(addr) \
UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 6f1a3a2..3ef73bf 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -5,6 +5,7 @@

#include "linux/module.h"
#include "linux/sched.h"
+#include "asm/smp.h"
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
diff --git a/include/asm-um/smp.h b/include/asm-um/smp.h
index d879eba..aeda665 100644
--- a/include/asm-um/smp.h
+++ b/include/asm-um/smp.h
@@ -23,6 +23,8 @@ extern inline void smp_cpus_done(unsigne
{
}

+extern struct task_struct *idle_threads[NR_CPUS];
+
#endif

#endif

2006-01-19 00:01:33

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 4/8] uml: fix "apples/bananas" typo


Fix stupid typo.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

arch/um/kernel/physmem.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index f3b583a..544665e 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -265,7 +265,7 @@ int init_maps(unsigned long physmem, uns
highmem_len = highmem_pages * sizeof(struct page);

total_pages = phys_pages + iomem_pages + highmem_pages;
- total_len = phys_len + iomem_pages + highmem_len;
+ total_len = phys_len + iomem_len + highmem_len;

if(kmalloc_ok){
map = kmalloc(total_len, GFP_KERNEL);

2006-01-19 00:01:33

by Blaisorblade

[permalink] [raw]
Subject: [PATCH 1/8] uml: typo fixup


Trivial innocent cosmetical fixup.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <[email protected]>
---

include/asm-um/ldt-x86_64.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/asm-um/ldt-x86_64.h b/include/asm-um/ldt-x86_64.h
index 175722a..57159f1 100644
--- a/include/asm-um/ldt-x86_64.h
+++ b/include/asm-um/ldt-x86_64.h
@@ -5,8 +5,8 @@
* Author: Bodo Stroesser <[email protected]>
*/

-#ifndef __ASM_LDT_I386_H
-#define __ASM_LDT_I386_H
+#ifndef __ASM_LDT_X86_64_H
+#define __ASM_LDT_X86_64_H

#include "asm/semaphore.h"
#include "asm/arch/ldt.h"

2006-01-19 03:29:18

by Jeff Dike

[permalink] [raw]
Subject: Re: [uml-devel] [PATCH 8/8] uml: avoid "CONFIG_NR_CPUS undeclared" bogus error messages

On Thu, Jan 19, 2006 at 12:55:23AM +0100, Paolo 'Blaisorblade' Giarrusso wrote:
> -extern struct task_struct *idle_threads[NR_CPUS];
> -

BTW, this isn't the only problem there. There are three declarations
towards the bottom with struct task_struct in them which have to be moved.

Jeff

2006-01-19 15:01:47

by Blaisorblade

[permalink] [raw]
Subject: Re: [uml-devel] [PATCH 8/8] uml: avoid "CONFIG_NR_CPUS undeclared" bogus error messages

On Thursday 19 January 2006 05:21, Jeff Dike wrote:
> On Thu, Jan 19, 2006 at 12:55:23AM +0100, Paolo 'Blaisorblade' Giarrusso
wrote:
> > -extern struct task_struct *idle_threads[NR_CPUS];
> > -
>
> BTW, this isn't the only problem there. There are three declarations
> towards the bottom with struct task_struct in them which have to be moved.

I saw that after, but let's say a thing which I always forgot to say:

we're often using void * in protos when we can't include a type declaration in
the needed file.

Gerd Knorr in his tty patch, instead, used forward declarations, like:

struct task_struct;

what about that?

Those functions probably should be moved anyway because they're useless there,
but I'm using this occasion to avoid forgetting this.
--
Inform me of my mistakes, so I can keep imitating Homer Simpson's "Doh!".
Paolo Giarrusso, aka Blaisorblade (Skype ID "PaoloGiarrusso", ICQ 215621894)
http://www.user-mode-linux.org/~blaisorblade


___________________________________
Yahoo! Messenger with Voice: chiama da PC a telefono a tariffe esclusive
http://it.messenger.yahoo.com

2006-01-19 18:52:04

by Jeff Dike

[permalink] [raw]
Subject: Re: [uml-devel] [PATCH 8/8] uml: avoid "CONFIG_NR_CPUS undeclared" bogus error messages

On Thu, Jan 19, 2006 at 04:01:28PM +0100, Blaisorblade wrote:
> Gerd Knorr in his tty patch, instead, used forward declarations, like:
>
> struct task_struct;
>
> what about that?

I don't think so. At least when you use void *, you are using a type
that's not incorrect. In userspace code, those task_structs start
referring to host task_structs, which is definitely very wrong.

> Those functions probably should be moved anyway because they're
> useless there

Yeah.

Jeff

2006-01-19 23:41:51

by Blaisorblade

[permalink] [raw]
Subject: Re: [uml-devel] [PATCH 8/8] uml: avoid "CONFIG_NR_CPUS undeclared" bogus error messages

On Thursday 19 January 2006 20:43, Jeff Dike wrote:
> On Thu, Jan 19, 2006 at 04:01:28PM +0100, Blaisorblade wrote:
> > Gerd Knorr in his tty patch, instead, used forward declarations, like:
> >
> > struct task_struct;
> >
> > what about that?

> I don't think so. At least when you use void *, you are using a type
> that's not incorrect. In userspace code, those task_structs start
> referring to host task_structs, which is definitely very wrong.

Possibly yes, but as long as we don't dereference the pointer (and in a
prototype you're not going to do that) there's no problem.

Using a type makes the code clearer, and it doesn't hide any warning GCC may
give (behaving well is left to us only).

In fact, btw (before I forget) we have currently the wrong errno used in
sys-i386/ldt.c. Just wrote the fix (it's adding a silly os_ptrace_ldt). Going
to compile and send.

> > Those functions probably should be moved anyway because they're
> > useless there

> Yeah.

> Jeff

--
Inform me of my mistakes, so I can keep imitating Homer Simpson's "Doh!".
Paolo Giarrusso, aka Blaisorblade (Skype ID "PaoloGiarrusso", ICQ 215621894)
http://www.user-mode-linux.org/~blaisorblade





___________________________________
Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB
http://mail.yahoo.it