diff -Naur -X exclude-files ac_cur/arch/um/drivers/net_kern.c ac/arch/um/drivers/net_kern.c
--- ac_cur/arch/um/drivers/net_kern.c	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/drivers/net_kern.c	Sat Nov  3 16:15:32 2001
@@ -31,6 +31,7 @@
 #include "mcast.h"
 #include "mcast_kern.h"
 #include "mconsole_kern.h"
+#include "init.h"
 
 LIST_HEAD(opened);
 
@@ -110,8 +111,53 @@
 	return(1);
 }
 
-__setup("eth", eth_setup);
+#ifdef CONFIG_UML_NET_ETHERTAP
+#define UML_NET_ETHERTAP_HELP	\
+"    eth[0-9]+=ethertap,<device>,<ethernet address>,<tap ip address>\n" \
+"    eth0=ethertap,tap0,,192.168.0.1\n\n"
+#else
+#define UML_NET_ETHERTAP_HELP
+#endif
+#ifdef CONFIG_UML_NET_TUNTAP
+#define UML_NET_TUNTAP_HELP \
+"    eth[0-9]+=tuntap,,<ethernet address>,<ip address>\n" \
+"    eth0=tuntap,,fe:fd:0:0:0:1,192.168.0.1\n\n"
+#else
+#define UML_NET_TUNTAP_HELP
+#endif
+#ifdef CONFIG_UML_NET_DAEMON
+#define UML_NET_DAEMON_HELP \
+"    eth[0-9]+=daemon,<ethernet address>,<type>,<control socket>,<data socket>\n" \
+"    eth0=daemon,unix,/tmp/uml.ctl,/tmp/uml.data\n\n"
+#else
+#define UML_NET_DAEMON_HELP
+#endif
+#ifdef CONFIG_UML_NET_SLIP
+#define UML_NET_SLIP_HELP \
+"    eth[0-9]+=slip,<slip ip>\n" \
+"    eth0=slip,192.168.0.1\n\n"
+#else
+#define UML_NET_SLIP_HELP
+#endif
+#ifdef CONFIG_UML_NET_MCAST
+#define UML_NET_MCAST_HELP \
+"    eth[0-9]+=mcast,<ethernet address>,<address>,<port>,<ttl>\n" \
+"    eth0=mcast,,224.2.3.4:5555,3\n\n"
+#else
+#define UML_NET_MCAST_HELP
+#endif
 
+__setup("eth", eth_setup);
+__uml_help(eth_setup,
+"eth[0-9]+=<transport>,<options>\n"
+"    Configure a network device.  Formats and examples follow (one \n"
+"    for each configured transport).\n\n"
+UML_NET_ETHERTAP_HELP
+UML_NET_TUNTAP_HELP
+UML_NET_DAEMON_HELP
+UML_NET_SLIP_HELP
+UML_NET_MCAST_HELP
+);
 int ndev = 0;
 
 static int uml_net_rx(struct net_device *dev)
diff -Naur -X exclude-files ac_cur/arch/um/drivers/ssl.c ac/arch/um/drivers/ssl.c
--- ac_cur/arch/um/drivers/ssl.c	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/drivers/ssl.c	Sat Nov  3 16:15:32 2001
@@ -16,6 +16,7 @@
 #include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
+#include "init.h"
 
 static int ssl_version = 1;
 
@@ -283,6 +284,7 @@
 }
 
 __setup("ssl", ssl_chan_setup);
+__channel_help(ssl_chan_setup, "ssl");
 
 static void ssl_exit(void)
 {
diff -Naur -X exclude-files ac_cur/arch/um/drivers/stdio_console.c ac/arch/um/drivers/stdio_console.c
--- ac_cur/arch/um/drivers/stdio_console.c	Sat Nov  3 16:14:54 2001
+++ ac/arch/um/drivers/stdio_console.c	Sat Nov  3 16:15:32 2001
@@ -21,6 +21,7 @@
 #include "chan.h"
 #include "user_util.h"
 #include "kern_util.h"
+#include "init.h"
 
 #define MAX_TTYS (8)
 
@@ -64,9 +65,8 @@
 	if(err < 0){
 		printk("Failed to open virtual console %d, errno = %d\n",
 		       line, err);
-		return(err);
 	}
-	return(0);
+	return(err);
 }
 
 static int open_console(int line, struct tty_struct *tty)
@@ -280,6 +280,7 @@
 }
 
 __setup("con", console_chan_setup);
+__channel_help(console_chan_setup, "con");
 
 static void console_exit(void)
 {
diff -Naur -X exclude-files ac_cur/arch/um/drivers/ubd.c ac/arch/um/drivers/ubd.c
--- ac_cur/arch/um/drivers/ubd.c	Sat Nov  3 16:13:06 2001
+++ ac/arch/um/drivers/ubd.c	Sat Nov  3 16:15:32 2001
@@ -25,6 +25,7 @@
 #include "kern_util.h"
 #include "kern.h"
 #include "mconsole_kern.h"
+#include "init.h"
 
 extern __u64 file_size(char *file);
 
@@ -201,6 +202,10 @@
 }
 
 __setup("fake_ide", fake_ide_setup);
+__uml_help(fake_ide_setup,
+"fake_ide\n"
+"    Create ide0 entries that map onto ubd devices.\n\n"
+);
 
 static int ubd_setup_common(char *str, int *index_out)
 {
@@ -268,6 +273,17 @@
 }
 
 __setup("ubd", ubd_setup);
+__uml_help(ubd_setup,
+"ubd<n>=<filename>\n"
+"    This is used to associate a device with a file in the underlying\n"
+"    filesystem. Usually, there is a filesystem in the file, but \n"
+"    that's not required. Swap devices containing swap files can be\n"
+"    specified like this. Also, a file which doesn't contain a\n"
+"    filesystem can have its contents read in the virtual \n"
+"    machine by running dd on the device. n must be in the range\n"
+"    0 to 7. Appending an 'r' to the number will cause that device\n"
+"    to be mounted read-only. For example ubd1r=./ext_fs\n\n"
+);
 
 static int fakehd(char *str)
 {
@@ -277,6 +293,10 @@
 }
 
 __setup("fakehd", fakehd);
+__uml_help(fakehd,
+"fakehd\n"
+"    Change the ubd device name to \"hd\".\n\n"
+);
 
 static void do_ubd_request(request_queue_t * q);
 
diff -Naur -X exclude-files ac_cur/arch/um/include/chan.h ac/arch/um/include/chan.h
--- ac_cur/arch/um/include/chan.h	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/include/chan.h	Sat Nov  3 16:15:32 2001
@@ -5,6 +5,7 @@
 
 #ifndef __TTY_H__
 #define __TTY_H__
+#include "init.h"
 
 struct chan {
 	enum { XTERM, PTY, SOCKET, FD, TTY, PTS, FILE_CHAN, COPY } type;
@@ -41,6 +42,13 @@
 	struct chan in;
 	struct chan out;
 };
+
+#define __channel_help(fn, prefix) \
+__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
+"    Attach a console or serial line to a host channel.  See\n" \
+"    http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
+"    description of this switch.\n\n" \
+);
 
 #define INIT_STATIC (0)
 #define INIT_ALL (1)
diff -Naur -X exclude-files ac_cur/arch/um/include/init.h ac/arch/um/include/init.h
--- ac_cur/arch/um/include/init.h	Wed Dec 31 19:00:00 1969
+++ ac/arch/um/include/init.h	Sat Nov  3 16:15:32 2001
@@ -0,0 +1,94 @@
+#ifndef _LINUX_UML_INIT_H
+#define _LINUX_UML_INIT_H
+
+/* These macros are used to mark some functions or
+ * initialized data (doesn't apply to uninitialized data)
+ * as `initialization' functions. The kernel can take this
+ * as hint that the function is used only during the initialization
+ * phase and free up used memory resources after
+ *
+ * Usage:
+ * For functions:
+ *
+ * You should add __init immediately before the function name, like:
+ *
+ * static void __init initme(int x, int y)
+ * {
+ *    extern int z; z = x * y;
+ * }
+ *
+ * If the function has a prototype somewhere, you can also add
+ * __init between closing brace of the prototype and semicolon:
+ *
+ * extern int initialize_foobar_device(int, int, int) __init;
+ *
+ * For initialized data:
+ * You should insert __initdata between the variable name and equal
+ * sign followed by value, e.g.:
+ *
+ * static int init_variable __initdata = 0;
+ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ *
+ * Don't forget to initialize data not at file scope, i.e. within a function,
+ * as gcc otherwise puts the data into the bss section and not into the init
+ * section.
+ *
+ * Also note, that this data cannot be "const".
+ */
+
+#ifndef _LINUX_INIT_H
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init          __attribute__ ((__section__ (".text.init")))
+#define __exit          __attribute__ ((unused, __section__(".text.exit")))
+#define __initdata      __attribute__ ((__section__ (".data.init")))
+
+#endif
+struct uml_param {
+        const char *str;
+        int (*setup_func)(char *, int *);
+};
+
+extern initcall_t __uml_initcall_start, __uml_initcall_end;
+extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
+extern const char *__uml_help_start, *__uml_help_end;
+
+#define __uml_initcall(fn)								\
+	static initcall_t __uml_initcall_##fn __uml_init_call = fn
+#define __uml_exitcall(fn)								\
+	static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
+
+extern struct uml_param __uml_setup_start, __uml_setup_end;
+
+#define __uml_postsetup(fn)								\
+	static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
+
+#define __non_empty_string(dummyname,string)						\
+	struct __uml_non_empty_string_struct_##dummyname				\
+	{										\
+		char _string[sizeof(string)-2];						\
+	}
+
+#define __uml_setup(str, fn, help...)							\
+	__non_empty_string(fn ##_setup, str);						\
+	__uml_help(fn, help);								\
+	static char __uml_setup_str_##fn[] __initdata = str;				\
+	static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }\
+
+#define __uml_help(fn, help...)								\
+	__non_empty_string(fn ##__help, help);						\
+	static char __uml_help_str_##fn[] __initdata = help;				\
+	static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
+
+/*
+ * Mark functions and data as being only used at initialization
+ * or exit time.
+ */
+#define __uml_init_setup	__attribute__ ((unused,__section__ (".uml.setup.init")))
+#define __uml_setup_help	__attribute__ ((unused,__section__ (".uml.help.init")))
+#define __uml_init_call		__attribute__ ((unused,__section__ (".uml.initcall.init")))
+#define __uml_postsetup_call	__attribute__ ((unused,__section__ (".uml.postsetup.init")))
+#define __uml_exit_call		__attribute__ ((unused,__section__ (".uml.exitcall.exit")))
+
+#endif /* _LINUX_UML_INIT_H */
diff -Naur -X exclude-files ac_cur/arch/um/include/initrd.h ac/arch/um/include/initrd.h
--- ac_cur/arch/um/include/initrd.h	Wed Dec 31 19:00:00 1969
+++ ac/arch/um/include/initrd.h	Sat Nov  3 16:15:32 2001
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __INITRD_USER_H__
+#define __INITRD_USER_H__
+
+extern int load_initrd(char *filename, void *buf, int size);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Naur -X exclude-files ac_cur/arch/um/include/mem_user.h ac/arch/um/include/mem_user.h
--- ac_cur/arch/um/include/mem_user.h	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/include/mem_user.h	Sat Nov  3 16:15:32 2001
@@ -37,12 +37,13 @@
 extern unsigned long host_task_size;
 extern unsigned long task_size;
 
+extern int init_mem_user(void);
 extern int create_mem_file(unsigned long len);
 extern void setup_range(int fd, char *driver, unsigned long start,
 			unsigned long usable, unsigned long total);
 extern void map(unsigned long virt, void *p, unsigned long len, int r,
 		int w, int x);
-extern void parse_iomem(char *str);
+extern int parse_iomem(char *str, int *add);
 extern void setup_memory(void);
 extern unsigned long find_iomem(char *driver, unsigned long *len_out);
 
diff -Naur -X exclude-files ac_cur/arch/um/kernel/Makefile ac/arch/um/kernel/Makefile
--- ac_cur/arch/um/kernel/Makefile	Sat Nov  3 16:14:09 2001
+++ ac/arch/um/kernel/Makefile	Sat Nov  3 16:15:32 2001
@@ -6,6 +6,10 @@
 	sysrq.o sys_call_table.o time.o time_kern.o tlb.o trap_kern.o \
 	trap_user.o uaccess_user.o um_arch.o umid.o user_util.o
 
+ifeq ($(CONFIG_BLK_DEV_INITRD), y)
+  OBJS += initrd_kern.o initrd_user.o
+endif
+
 export-objs = ksyms.o process_kern.o signal_kern.o user_syms.o
 
 UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
diff -Naur -X exclude-files ac_cur/arch/um/kernel/initrd_kern.c ac/arch/um/kernel/initrd_kern.c
--- ac_cur/arch/um/kernel/initrd_kern.c	Wed Dec 31 19:00:00 1969
+++ ac/arch/um/kernel/initrd_kern.c	Sat Nov  3 16:15:32 2001
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/bootmem.h"
+
+#include "linux/blk.h"
+#include "user_util.h"
+#include "initrd.h"
+#include "init.h"
+
+static char *initrd __initdata = NULL;
+static int __init read_initrd(void)
+{
+	void *area;
+	int size;
+
+	if(initrd == NULL) return 0;
+	size = file_size(initrd);
+	if(size < 0) return 0;
+	area = alloc_bootmem(size);
+	if(area == NULL) return 0;
+	if(load_initrd(initrd, area, size) == -1) return 0;
+	initrd_start = (unsigned long) area;
+	initrd_end = initrd_start + size;
+	return 0;
+}
+static int __init uml_initrd_setup(char *line, int *add)
+{
+	initrd = line;
+	return 0;
+}
+__uml_setup("initrd=", uml_initrd_setup, 
+"initrd=<initrd image>\n"
+"    This is used to boot UML from an initrd image.  The argument is the\n"
+"    name of the file containing the image\n"
+);
+__uml_postsetup(read_initrd);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Naur -X exclude-files ac_cur/arch/um/kernel/initrd_user.c ac/arch/um/kernel/initrd_user.c
--- ac_cur/arch/um/kernel/initrd_user.c	Wed Dec 31 19:00:00 1969
+++ ac/arch/um/kernel/initrd_user.c	Sat Nov  3 16:15:32 2001
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "initrd.h"
+
+int load_initrd(char *filename, void *buf, int size)
+{
+	int fd, n;
+
+	if((fd = open(filename, O_RDONLY)) == -1){
+		printk("Opening '%s' failed - errno = %d\n", filename, errno);
+		return(-1);
+	}
+	if((n = read(fd, buf, size)) != size){
+		printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
+		       size, filename, n, errno);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Naur -X exclude-files ac_cur/arch/um/kernel/mem.c ac/arch/um/kernel/mem.c
--- ac_cur/arch/um/kernel/mem.c	Sat Nov  3 16:14:40 2001
+++ ac/arch/um/kernel/mem.c	Sat Nov  3 16:15:32 2001
@@ -19,6 +19,7 @@
 #include "kern_util.h"
 #include "mem_user.h"
 #include "kern.h"
+#include "init.h"
 
 unsigned long high_physmem;
 
@@ -39,6 +40,7 @@
 static unsigned long totalram_pages = 0;
 
 extern char __init_begin, __init_end;
+extern long physmem_size;
 
 int kmalloc_ok = 0;
 
@@ -193,6 +195,22 @@
 {
 	kmem_top = new;
 }
+
+static int __init uml_mem_setup(char *line, int *add)
+{
+	char *retptr;
+	physmem_size = memparse(line,&retptr);
+	return 0;
+}
+__uml_setup("mem=",uml_mem_setup,
+"mem=<Amount of desired ram>\n"
+"    This controls how much \"physical\" memory the kernel allocates\n"
+"    for the system. The size is specified as a number followed by\n"
+"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
+"    This is not related to the amount of memory in the physical\n"
+"    machine. It can be more, and the excess, if it's ever used, will\n"
+"    just be swapped out.\n        Example: mem=64M\n\n"
+);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Naur -X exclude-files ac_cur/arch/um/kernel/mem_user.c ac/arch/um/kernel/mem_user.c
--- ac_cur/arch/um/kernel/mem_user.c	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/kernel/mem_user.c	Sat Nov  3 16:15:32 2001
@@ -41,6 +41,8 @@
 #include <sys/mman.h>
 #include "kern_util.h"
 #include "user.h"
+#include "user_util.h"
+#include "init.h"
 
 struct mem_region {
 	struct mem_region *next;
@@ -55,21 +57,14 @@
 
 struct mem_region *mem_list = &physmem_region;
 
+#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
+
 int create_mem_file(unsigned long len)
 {
-	char tempname[sizeof("/tmp/vm_file-XXXXXX\0")];
 	int fd;
 	char zero;
 
-	strcpy(tempname, "/tmp/vm_file-XXXXXX");
-	if((fd = mkstemp(tempname)) < 0){
-		perror("open - cannot create /tmp/vm_file-XXXXXX");
-		exit(1);
-	}
-	if(unlink(tempname) < 0){
-		perror("unlink");
-		exit(1);
-	}
+	fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
 	if (fchmod(fd, 0777) < 0){
 		perror("fchmod");
 		exit(1);
@@ -137,7 +132,7 @@
 	}
 }
 
-void parse_iomem(char *str)
+static int __init parse_iomem(char *str, int *add)
 {
 	struct stat buf;
 	char *file, *driver;
@@ -147,21 +142,26 @@
 	file = strchr(str,',');
 	if(file == NULL){
 		printk(__FUNCTION__ " failed to parse iomem\n");
-		return;
+		return 1;
 	}
 	*file = '\0';
 	file++;
 	fd = open(file, O_RDWR);
 	if(fd < 0){
 		perror("Couldn't open io file");
-		return;
+		return 1;
 	}
 	if(fstat(fd, &buf) < 0) {
 		perror(__FUNCTION__ "fstat - cannot fstat file");
 		exit(1);
 	}
 	setup_range(fd, driver, -1, buf.st_size, buf.st_size);
+	return 0;
 }
+__uml_setup("iomem=",parse_iomem,
+"iomem=<name>,<file>\n"
+"    Configure <file> as a named IO memory region named <name>.\n\n"
+);
 
 void map(unsigned long virt, void *p, unsigned long len, int r,
 	 int w, int x)
diff -Naur -X exclude-files ac_cur/arch/um/kernel/process_kern.c ac/arch/um/kernel/process_kern.c
--- ac_cur/arch/um/kernel/process_kern.c	Sat Nov  3 16:14:40 2001
+++ ac/arch/um/kernel/process_kern.c	Sat Nov  3 16:15:32 2001
@@ -29,6 +29,7 @@
 #include "kern.h"
 #include "signal_kern.h"
 #include "signal_user.h"
+#include "init.h"
 
 struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
 
@@ -737,11 +738,26 @@
 	return(new);
 }
 
+static int jail = 0;
+
+static int __init jail_setup(char *line, int *add)
+{
+	jail = 1;
+	*add = 1;
+	return(0);
+}
+
+__uml_setup("jail", jail_setup,
+"jail\n"
+"    Enables the protection of kernel memory from processes\n\n"
+);
+
 void unprotect_kernel_mem(void)
 {
 	unsigned long start_stack, end_stack;
 
-	if(current_task == &init_task) return;
+	if(!jail) return;
+	if(current == &init_task) return;
 	start_stack = (unsigned long) current + PAGE_SIZE;
 	end_stack = (unsigned long) current + PAGE_SIZE * 4;
 	protect(uml_physmem, start_stack - uml_physmem, 1, 1, 1);
@@ -752,7 +768,8 @@
 {
 	unsigned long start_stack, end_stack;
 
-	if(current_task == &init_task) return;
+	if(!jail) return;
+	if(current == &init_task) return;
 	start_stack = (unsigned long) current + PAGE_SIZE;
 	end_stack = (unsigned long) current + PAGE_SIZE * 4;
 	protect(uml_physmem, start_stack - uml_physmem, 1, 0, 1);
diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_kern.c ac/arch/um/kernel/trap_kern.c
--- ac_cur/arch/um/kernel/trap_kern.c	Sat Nov  3 16:14:09 2001
+++ ac/arch/um/kernel/trap_kern.c	Sat Nov  3 16:15:32 2001
@@ -305,6 +305,30 @@
 	return(pid);
 }
 
+#ifdef notdef /* Put this back in when it does something useful */
+static int __init uml_gdb_init_setup(char *line, int *add)
+{
+	gdb_init = line;
+	return 0;
+}
+
+__uml_setup("gdb=", uml_gdb_init_setup, 
+"gdb=<channel description>\n\n"
+);
+#endif
+
+static int __init uml_gdb_pid_setup(char *line, int *add)
+{
+	gdb_pid = simple_strtoul(line, NULL, 0);
+	return 0;
+}
+
+__uml_setup("gdb-pid=", uml_gdb_pid_setup, 
+"gdb-pid=<pid>\n"
+"    gdb-pid is used to attach an external debugger to UML.  This may be\n"
+"    an already-running gdb or a debugger-like process like strace.\n\n"
+);
+
 #else
 
 void debugger_signal(int status, pid_t pid){ }
diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_user.c ac/arch/um/kernel/trap_user.c
--- ac_cur/arch/um/kernel/trap_user.c	Sat Nov  3 16:14:09 2001
+++ ac/arch/um/kernel/trap_user.c	Sat Nov  3 16:15:32 2001
@@ -25,6 +25,7 @@
 #include "user.h"
 #include "process.h"
 #include "sysdep/sigcontext.h"
+#include "init.h"
 
 static void signal_segv(int sig)
 {
@@ -283,6 +284,31 @@
 	return(0);
 }
 
+static int __init uml_debugtrace_setup(char *line, int *add)
+{
+	debug_trace = 1;
+	return 0;
+}
+__uml_setup("debugtrace=",uml_debugtrace_setup,
+"debugtrace\n"
+"    Causes the tracing thread to pause until it is attached by a\n"
+"    debugger and continued.  This is mostly for debugging crashes\n"
+"    early during boot, and should be pretty much obsoleted by\n"
+"    the debug switch.\n\n"
+);
+
+static int __init uml_honeypot_setup(char *line, int *add)
+{
+	honeypot = 1;
+	return 0;
+}
+__uml_setup("honeypot", uml_honeypot_setup, 
+"honeypot\n"
+"    This makes UML put process stacks in the same location as they are\n"
+"    on the host, allowing expoits such as stack smashes to work against\n"
+"    UML.\n\n"
+);
+
 int nsegfaults = 0;
 
 void segv_handler(int sig, void *sc, int usermode)
@@ -377,6 +403,22 @@
 	irq_handler(sig, sc);
 	timer_ready = 1;
 }
+
+static int __init uml_debug_setup(char *line, int *add)
+{
+	debug = 1;
+	if(!strcmp(line, "=go")){
+		debug_stop = 0;
+		*add = 0;
+	}
+	return 0;
+}
+__uml_setup("debug",uml_debug_setup,
+"debug\n"
+"    Starts up the kernel under the control of gdb. See the \n"
+"    kernel debugging tutorial and the debugging session pages\n"
+"    at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
+);
 
 void do_longjmp(void *p)
 {
diff -Naur -X exclude-files ac_cur/arch/um/kernel/um_arch.c ac/arch/um/kernel/um_arch.c
--- ac_cur/arch/um/kernel/um_arch.c	Sat Nov  3 16:14:40 2001
+++ ac/arch/um/kernel/um_arch.c	Sat Nov  3 16:15:32 2001
@@ -12,9 +12,6 @@
 #include "linux/bootmem.h"
 #include "linux/spinlock.h"
 #include "linux/utsname.h"
-#ifdef CONFIG_BLK_DEV_INITRD
-#include "linux/blk.h"
-#endif
 #include "asm/page.h"
 #include "asm/pgtable.h"
 #include "asm/ptrace.h"
@@ -30,6 +27,8 @@
 #include "mprot.h"
 #include "mem_user.h"
 #include "umid.h"
+#include "initrd.h"
+#include "init.h"
 
 extern __u64 file_size(char *file);
 
@@ -128,6 +127,9 @@
 static char *argv1_begin = NULL;
 static char *argv1_end = NULL;
 
+static int have_root __initdata = 0;
+long physmem_size = 32 * 1024 * 1024;
+
 void set_cmdline(char *cmd)
 {
 	if(honeypot) return;
@@ -139,78 +141,89 @@
 }
 
 static char *usage_string = 
-"User Mode Linux v%s"
-" available at http://user-mode-linux.sourceforge.net/\n\n"
-"--help\n    Prints this message\n"
-"--version\n    Gives the version number of the kernel\n"
+"User Mode Linux v%s\n"
+"	available at http://user-mode-linux.sourceforge.net/\n\n";
+
+static int __init uml_version_setup(char *line, int *add)
+{
+	printf("%s\n", system_utsname.release);
+	exit(0);
+}
+
+__uml_setup("--version", uml_version_setup,
+"--version\n"
+"    Prints the version number of the kernel\n\n"
+);
+
+static int __init uml_root_setup(char *line, int *add)
+{
+	have_root = 1;
+	return 0;
+}
+__uml_setup("root=", uml_root_setup,
 "root=<file containing the root fs>\n"
 "    This is actually used by the generic kernel in exactly the same\n"
 "    way as in any other kernel. If you configure a number of block\n"
 "    devices and want to boot off something other than ubd0, you \n"
 "    would use something like:\n"
 "        root=/dev/ubd5\n\n"
-"mem=<Amount of desired ram>\n"
-"    This controls how much \"physical\" memory the kernel allocates\n"
-"    for the system. The size is specified as a number followed by\n"
-"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
-"    This is not related to the amount of memory in the physical\n"
-"    machine. It can be more, and the excess, if it's ever used, will\n"
-"    just be swapped out.\n        Example: mem=64M\n\n"
+);
+
 #ifdef CONFIG_SMP
+__uml_setup("ncpus=", uml_ncpus_setup,
 "ncpus=<# of desired CPUs>\n"
 "    This tells an SMP kernel how many virtual processors to start.\n"
 "    Currently, this has no effect because SMP isn't enabled.\n\n" 
+);
 #endif
-"debugtrace\n"
-"    Causes the tracing thread to pause until it is attached by a\n"
-"    debugger and continued. This is mostly for debugging crashes\n"
-"    early during boot, and should be pretty much obsoleted by\n"
-"    the debug switch.\n\n"
-"debug\n"
-"    Starts up the kernel under the control of gdb. See the \n"
-"    kernel debugging tutorial and the debugging session pages\n"
-"    at http://user-mode-linux.sourceforge.net/ for more information\n\n"
-"umn=<ip-address>\n"
-"    This sets the ip address of the host side of the slip device \n"
-"    that the umn device configures. This is necessary if you want\n"
-"    to set up networking, but your local net isn't 192.168.0.x,\n"
-"    or you want to run multiple virtual machines on a network,\n"
-"    in which case, you need to assign different ip addresses to the\n"
-"    different machines.\n\n"
-"ubd<n>=<filename>\n"
-"    This is used to associate a device with a file in the underlying\n"
-"    filesystem. Usually, there is a filesystem in the file, but \n"
-"    that's not required. Swap devices containing swap files can be\n"
-"    specified like this. Also, a file which doesn't contain a\n"
-"    filesystem can have its contents read in the virtual \n"
-"    machine by running dd on the device. n must be in the range\n"
-"    0 to 7. Appending an 'r' to the number will cause that device\n"
-"    to be mounted read-only. For example ubd1r=./ext_fs\n\n"
-"umid=<name>\n"
-"    This is used to assign a unique identity to this UML machine\n"
-"    Used for naming the pid file and console socket\n";
 
-static void Usage(void)
+static int __init Usage(char *line, int *add)
 {
+ 	const char **p;
+
 	printf(usage_string, system_utsname.release);
+ 	p = &__uml_help_start;
+ 	while (p < &__uml_help_end) {
+ 		printf("%s", *p);
+ 		p++;
+ 	}
 	exit(0);
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-static void read_initrd(char *initrd)
+__uml_setup("--help", Usage,
+"--help\n"
+"    Prints this message\n\n"
+);
+
+static int __init uml_checksetup(char *line, int *add)
 {
-	void *area;
-	int size;
+	struct uml_param *p;
 
-	size = file_size(initrd);
-	if(size < 0) return;
-	area = alloc_bootmem(size);
-	if(area == NULL) return;
-	if(load_initrd(initrd, area, size) == -1) return;
-	initrd_start = (unsigned long) area;
-	initrd_end = initrd_start + size;
+	p = &__uml_setup_start;
+	while(p < &__uml_setup_end) {
+		int n;
+
+		n = strlen(p->str);
+		if(!strncmp(line, p->str, n)){
+			if (p->setup_func(line + n, add))
+				return 1;
+		}
+		p++;
+	}
+	return 0;
+}
+
+static void __init uml_postsetup(void)
+{
+	initcall_t *p;
+
+	p = &__uml_postsetup_start;
+	while(p < &__uml_postsetup_end){
+		(*p)();
+		p++;
+	}
+	return;
 }
-#endif
 
 extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
 extern int debug_trace;
@@ -218,14 +231,10 @@
 int linux_main(int argc, char **argv)
 {
 	unsigned long start_pfn, end_pfn, bootmap_size;
-	unsigned long physmem_size, virtmem_size;
-	unsigned int i, have_root, add;
-	char *retptr;
+	unsigned long virtmem_size;
+	unsigned int i, add;
 	void *sp;
 	void *brk_start;
-#ifdef CONFIG_BLK_DEV_INITRD
-	char *initrd = NULL;
-#endif
 
 	remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext));
 	remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata));
@@ -235,57 +244,10 @@
  	/* Start physical memory at least 4M after the current brk */
  	uml_physmem = ROUND_4M(brk_start) + (1 << 22);
  
-	/* Create fake command line from argv[]. */
-	have_root = 0;
-	physmem_size = 32 * 1024 * 1024;
-	virtmem_size = physmem_size;
 	for (i = 1; i < argc; i++){
 		if((i == 1) && (argv[i][0] == ' ')) continue;
 		add = 1;
-		if(!strncmp(argv[i], "root=", strlen("root="))) have_root = 1;
-		else if(!strncmp(argv[i], "mem=", strlen("mem="))) 
-			physmem_size = memparse(argv[i] + strlen("mem="), 
-						&retptr);
-#ifdef CONFIG_SMP
-		else if(!strncmp(argv[i], "ncpus=", strlen("ncpus=")))
-			ncpus = strtoul(argv[i] + strlen("ncpus="), NULL, 10);
-#endif
-		else if(!strcmp(argv[i], "debugtrace")) debug_trace = 1;
-		else if(!strncmp(argv[i], "debug", strlen("debug"))){
-			debug = 1;
-			debug_stop = 1;
-			if(!strcmp(argv[i], "debug=go")){
-				debug_stop = 0;
-				add = 0;
-			}
-		}
-#ifdef CONFIG_PT_PROXY
-		else if(!strncmp(argv[i], "gdb=", strlen("gdb=")))
-			gdb_init = &argv[i][strlen("gdb=")];
-		else if(!strncmp(argv[i], "gdb-pid=", strlen("gdb-pid=")))
-			gdb_pid = simple_strtoul(&argv[i][strlen("gdb-pid=")],
-						 NULL, 0);
-#endif
-		else if(!strncmp(argv[i], "umid=", strlen("umid="))){
-			set_umid(&argv[i][strlen("umid=")]);
-		}
-		else if(!strncmp(argv[i], "iomem=", strlen("iomem="))){
-			parse_iomem(&argv[i][strlen("iomem=")]);
-		}
-		else if(!strcmp(argv[i], "honeypot")){
-			honeypot = 1;
-		}
-		else if(!strcmp(argv[i], "--version")){
-                        printf("%s\n", system_utsname.release);
-			exit(0);
-		}
-		else if(!strcmp(argv[i], "--help")){
-                        Usage();
-                }
-#ifdef CONFIG_BLK_DEV_INITRD
-		else if(!strncmp(argv[i], "initrd=", strlen("initrd=")))
-			initrd = &argv[i][strlen("initrd=")];
-#endif
+		uml_checksetup(argv[i], &add);
 		if(add) add_arg(saved_command_line, argv[i]);
 	}
 	if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
@@ -324,9 +286,7 @@
 	free_bootmem(__pa(uml_physmem) + bootmap_size, 
 		     high_physmem - uml_physmem - bootmap_size);
 
-#ifdef CONFIG_BLK_DEV_INITRD
-	if(initrd != NULL) read_initrd(initrd);
-#endif
+  	uml_postsetup();
 	init_task.thread.kernel_stack = (unsigned long) &init_task + 
 		2 * PAGE_SIZE;
 #ifndef CONFIG_SMP
diff -Naur -X exclude-files ac_cur/arch/um/kernel/umid.c ac/arch/um/kernel/umid.c
--- ac_cur/arch/um/kernel/umid.c	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/kernel/umid.c	Sat Nov  3 16:15:32 2001
@@ -9,49 +9,78 @@
 #include <signal.h>
 #include "user.h"
 #include "umid.h"
+#include "init.h"
 
 #define UMID_LEN 64
+#define UML_DIR "/tmp/uml/"
 
 static char umid[UMID_LEN] = { 0 };
+static char *uml_dir = UML_DIR;
 
 static int umid_inited = 0;
 
-int umid_file_name(char *name, char *buf, int len)
+static int make_umid(void);
+
+static int __init set_umid(char *name, int *add)
+{
+	if(umid_inited){
+		printk("Unique machine name can't be set twice\n");
+		return(-1);
+	}
+
+	if(strlen(name) > UMID_LEN - 1)
+		printk("Unique machine name is being truncated to %s "
+		       "characters\n", UMID_LEN);
+	strncpy(umid, name, UMID_LEN - 1);
+	umid[UMID_LEN - 1] = '\0';
+
+	umid_inited = 1;
+	return 0;
+}
+
+__uml_setup("umid=", set_umid,
+"umid=<name>\n"
+"    This is used to assign a unique identity to this UML machine\n"
+"    This is used for naming the pid file and management console socket\n\n"
+);
+
+int __init umid_file_name(char *name, char *buf, int len)
 {
 	int n;
 
-	if(!umid_inited && set_umid(NULL)) return(-1);
+	if(!umid_inited && make_umid()) return(-1);
 
-	n = sizeof("/tmp/uml") + strlen(umid) + sizeof("/") + strlen(name) + 1;
+	n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
 	if(n > len){
 		printk("umid_file_name : buffer too short\n");
 		return(-1);
 	}
 
-	sprintf(buf, "/tmp/uml/%s/%s", umid, name);
+	sprintf(buf, "%s%s/%s", uml_dir, umid, name);
 	return(0);
 }
 
 extern int tracing_pid;
 
-static void create_pid_file(void)
+static int __init create_pid_file(void)
 {
-	char file[sizeof("/tmp/uml/") + UMID_LEN + sizeof("/pid\0")];
+	char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
 	char pid[sizeof("nnnnn\0")];
 	int fd;
 
-	if(umid_file_name("pid", file, sizeof(file))) return;
+	if(umid_file_name("pid", file, sizeof(file))) return 0;
 
 	if((fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0){
 		printk("Open of machine pid file \"%s\" failed - "
 		       "errno = %d\n", file, errno);
-		return;
+		return 0;
 	}
 
 	sprintf(pid, "%d\n", (tracing_pid == -1) ?  getpid() : tracing_pid);
 	if(write(fd, pid, strlen(pid)) != strlen(pid))
 		printk("Write of pid file failed - errno = %d\n", errno);
 	close(fd);
+	return 0;
 }
 
 static int actually_do_remove(char *dir)
@@ -93,10 +122,10 @@
 
 void remove_umid_dir(void)
 {
-	char dir[sizeof("/tmp/uml/") + UMID_LEN + 1];
+	char dir[strlen(uml_dir) + UMID_LEN + 1];
 	if(!umid_inited) return;
 
-	sprintf(dir, "/tmp/uml/%s", umid);
+	sprintf(dir, "%s%s", uml_dir, umid);
 	actually_do_remove(dir);
 }
 
@@ -105,9 +134,9 @@
 	return(umid);
 }
 
-static int not_dead_yet(char *dir)
+int not_dead_yet(char *dir)
 {
-	char file[sizeof("/tmp/uml/") + UMID_LEN + sizeof("/pid\0")];
+	char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
 	char pid[sizeof("nnnnn\0")], *end;
 	int dead, fd, p;
 
@@ -133,37 +162,54 @@
 			       "errno = %d\n", file, errno);
 			dead = 1;
 		}
-		if((kill(p, 0) < 0) && (errno == ESRCH)) dead = 1;
+		if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
+		   (p == tracing_pid)) 
+			dead = 1;
 	}
 	if(!dead) return(1);
 	return(actually_do_remove(dir));
 	return(0);
 }
 
-int set_umid(char *name)
+static int __init set_uml_dir(char *name, int *add)
 {
-	int fd, err;
-	char tmp[sizeof("/tmp/uml/") + UMID_LEN + 1];
-
-	if(umid_inited){
-		printk("Unique machine name can't be set twice\n");
-		return(-1);
+	if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
+		uml_dir = malloc(strlen(name) + 1);
+		if(uml_dir == NULL){
+			printk("Failed to malloc uml_dir - error = %d\n",
+			       errno);
+			uml_dir = name;
+			return(0);
+		}
+		sprintf(uml_dir, "%s/", name);
 	}
+	else uml_dir = name;
+	return 0;
+}
 
-	if((mkdir("/tmp/uml", 0777) < 0) && (errno != EEXIST)){
-		printk("Failed to create /tmp/uml - errno = %s\n", errno);
+static int __init make_uml_dir(void)
+{
+	if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
+	        printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
 		return(-1);
 	}
+	return 0;
+}
+
+static int __init make_umid(void)
+{
+	int fd, err;
+	char tmp[strlen(uml_dir) + UMID_LEN + 1];
 
-	strcpy(tmp, "/tmp/uml/");
+	strcpy(tmp, uml_dir);
 
-	if(name == NULL){
+	if(*umid == 0){
 		strcat(tmp, "XXXXXX");
 		fd = mkstemp(tmp);
 		if(fd < 0){
 			printk("set_umid - mkstemp failed, errno = %d\n",
 			       errno);
-			return(-1);
+			return(1);
 		}
 
 		close(fd);
@@ -172,16 +218,10 @@
 		 * for directories.
 		 */
 		unlink(tmp);
-		name = &tmp[strlen("/tmp/uml/")];
+		strcpy(umid, &tmp[strlen(uml_dir)]);
 	}
-
-	if(strlen(name) > UMID_LEN - 1)
-		printk("Unique machine name is being truncated to %s "
-		       "characters\n", UMID_LEN);
-	strncpy(umid, name, UMID_LEN - 1);
-	umid[UMID_LEN - 1] = '\0';
 	
-	sprintf(tmp, "/tmp/uml/%s", umid);
+	sprintf(tmp, "%s%s", uml_dir, umid);
 
 	if((err = mkdir(tmp, 0777)) < 0){
 		if(errno == EEXIST){
@@ -197,10 +237,17 @@
 		return(-1);
 	}
 
-	umid_inited = 1;
-	create_pid_file();
 	return(0);
 }
+
+__uml_setup("uml_dir=", set_uml_dir,
+"uml_dir=<directory>\n"
+"    The location to place the pid and umid files.\n\n"
+);
+
+__uml_postsetup(make_uml_dir);
+__uml_postsetup(make_umid);
+__uml_postsetup(create_pid_file);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Naur -X exclude-files ac_cur/arch/um/kernel/user_util.c ac/arch/um/kernel/user_util.c
--- ac_cur/arch/um/kernel/user_util.c	Sat Nov  3 16:13:06 2001
+++ ac/arch/um/kernel/user_util.c	Sat Nov  3 16:15:32 2001
@@ -13,6 +13,7 @@
 #include <sys/ptrace.h>
 #include <sys/mount.h>
 #include <sys/utsname.h>
+#include <sys/param.h>
 #include <asm/types.h>
 #include <ctype.h>
 #include <signal.h>
@@ -26,6 +27,7 @@
 #include "kern_util.h"
 #include "user.h"
 #include "mem_user.h"
+#include "init.h"
 
 #define COMMAND_LINE_SIZE _POSIX_ARG_MAX
 
@@ -152,22 +154,6 @@
 	return(buf.st_size);
 }
 
-int load_initrd(char *filename, void *buf, int size)
-{
-	int fd, n;
-
-	if((fd = open(filename, O_RDONLY)) == -1){
-		printk("Opening '%s' failed - errno = %d\n", filename, errno);
-		return(-1);
-	}
-	if((n = read(fd, buf, size)) != size){
-		printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
-		       size, filename, n, errno);
-		return(-1);
-	}
-	return(0);
-}
-
 void stop(void)
 {
 	while(1) sleep(1000000);
@@ -323,6 +309,62 @@
 void close_fd(int fd)
 {
 	close(fd);
+}
+
+char *tempdir = NULL;
+
+static void __init find_tempdir(void)
+{
+	char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
+	int i;
+	char *dir = NULL;
+
+	if(tempdir != NULL) return;	/* We've already been called */
+	for(i = 0; dirs[i]; i++){
+		dir = getenv(dirs[i]);
+		if(dir != NULL) break;
+	}
+	if(dir == NULL) dir = "/tmp";
+	else if(*dir == '\0') dir = NULL;
+	if(dir != NULL) {
+		tempdir = malloc(strlen(dir) + 2);
+		if(tempdir == NULL){
+			fprintf(stderr, "Failed to malloc tempdir, "
+				"errno = %d\n", errno);
+			return;
+		}
+		strcpy(tempdir, dir);
+		strcat(tempdir, "/");
+	}
+}
+
+int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+{
+	char tempname[MAXPATHLEN];
+	int fd;
+
+	find_tempdir();
+	if (*template != '/')
+		strcpy(tempname, tempdir);
+	else
+		*tempname = 0;
+	strcat(tempname, template);
+	if((fd = mkstemp(tempname)) < 0){
+		fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
+			strerror(errno));
+		return -1;
+	}
+	if(do_unlink && (unlink(tempname) < 0)){
+		perror("unlink");
+		return -1;
+	}
+	if(out_tempname){
+		if((*out_tempname = strdup(tempname)) == NULL){
+			perror("strdup");
+			return -1;
+		}
+	}
+	return(fd);
 }
 
 /*
diff -Naur -X exclude-files ac_cur/arch/um/link.ld.in ac/arch/um/link.ld.in
--- ac_cur/arch/um/link.ld.in	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/link.ld.in	Sat Nov  3 16:15:32 2001
@@ -11,27 +11,14 @@
   _stext = .;
   __init_begin = .;
   .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
-  __initcall_end = .;
   . = ALIGN(4096);
-  __init_end = .;
-  __exitcall_begin = .;
-  .exitcall : { *(.exitcall.exit) }
-  __exitcall_end = .;
-
   .text      :
   {
     *(.text)
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
     *(.gnu.linkonce.t*)
-  } =0x9090
+  }
   .kstrtab : { *(.kstrtab) }
 
   . = ALIGN(16);		/* Exception table */
@@ -47,13 +34,38 @@
   .rodata1   : { *(.rodata1) }
   _etext = .;
   PROVIDE (etext = .);
-  /* Adjust the address for the data segment.  We want to adjust up to
-     the same address within the page on the next page up.  */
-  . = ALIGN(0x1000) + (. & (0x1000 - 1));
+
+  . = ALIGN(4096);
+  PROVIDE (_sdata = .);
+  __uml_setup_start = .;
+  .uml.setup.init : { *(.uml.setup.init) }
+  __uml_setup_end = .;
+  __uml_help_start = .;
+  .uml.help.init : { *(.uml.help.init) }
+  __uml_help_end = .;
+  __uml_postsetup_start = .;
+  .uml.postsetup.init : { *(.uml.postsetup.init) }
+  __uml_postsetup_end = .;
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+  __uml_initcall_start = .;
+  .uml.initcall.init : { *(.uml.initcall.init) }
+  __uml_initcall_end = .;
+  __init_end = .;
+  __exitcall_begin = .;
+  .exitcall : { *(.exitcall.exit) }
+  __exitcall_end = .;
+  __uml_exitcall_begin = .;
+  .uml.exitcall : { *(.uml.exitcall.exit) }
+  __uml_exitcall_end = .;
+
+  .data.init : { *(.data.init) }
   .data    :
   {
-    _sdata = .;
-    PROVIDE (sdata = .);
     . = ALIGN(16384);		/* init_task */
     *(.data.init_task)
     *(.data)
diff -Naur -X exclude-files ac_cur/arch/um/main.c ac/arch/um/main.c
--- ac_cur/arch/um/main.c	Sat Nov  3 16:14:09 2001
+++ ac/arch/um/main.c	Sat Nov  3 16:15:32 2001
@@ -17,6 +17,7 @@
 #include "kern_util.h"
 #include "mem_user.h"
 #include "user.h"
+#include "init.h"
 
 unsigned long stacksizelim;
 
@@ -56,6 +57,16 @@
 	task_size = host_task_size - 0x20000000;
 }
 
+static __init void do_uml_initcalls(void)
+{
+	initcall_t *call;
+
+	call = &__uml_initcall_start;
+	while (call < &__uml_initcall_end){;
+		(*call)();
+		call++;
+	}
+}
 int main(int argc, char **argv, char **envp)
 {
 	struct termios tt;
@@ -106,6 +117,7 @@
 	}
 	new_argv[argc] = NULL;
 
+	do_uml_initcalls();
 	ret = linux_main(argc, argv);
 	
 	/* Reboot */
diff -Naur -X exclude-files ac_cur/arch/um/ptproxy/proxy.c ac/arch/um/ptproxy/proxy.c
--- ac_cur/arch/um/ptproxy/proxy.c	Sat Nov  3 16:12:55 2001
+++ ac/arch/um/ptproxy/proxy.c	Sat Nov  3 16:15:32 2001
@@ -213,8 +213,7 @@
 	if(err) return(err);
 	slave = CHAN_OUT_FD(gdb_chan);
 	if((child = fork()) == 0){
-		char tempname[sizeof("/tmp/gdb_init-XXXXXX")];
-		char arg[sizeof("--command=/tmp/gdb_init-XXXXXX")];
+		char *tempname = NULL;
 		int fd;
 
 	        if(setsid() < 0) perror("setsid");
@@ -236,13 +235,11 @@
 			exit(1);
 #endif
 		}
-		strcpy(tempname, "/tmp/gdb_init-XXXXXX");
-		if((fd = mkstemp(tempname)) < 0){
-			printk("start_debugger : mkstmp failed, errno = %d\n",
+		if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
+			printk("start_debugger : make_tempfile failed, errno = %d\n",
 			       errno);
 			exit(1);
 		}
-		sprintf(arg, "--command=%s", tempname);
 		write(fd, "att 1\n", strlen("att 1\n"));
 		write(fd, "b panic\n", strlen("b panic\n"));
 		write(fd, "b stop\n", strlen("b stop\n"));
@@ -260,7 +257,7 @@
 			       "errno = %d\n", errno);
 			exit(1);
 		}
-		execlp("gdb", "gdb", arg, prog, NULL);
+		execlp("gdb", "gdb", "--command", tempname, prog, NULL);
 		printk("start_debugger : exec of gdb failed, errno = %d\n", 
 		       errno);
 	}