aboutsummaryrefslogtreecommitdiff
path: root/arch/um/os-Linux
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/os-Linux
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/um/os-Linux')
-rw-r--r--arch/um/os-Linux/Makefile13
-rw-r--r--arch/um/os-Linux/drivers/Makefile13
-rw-r--r--arch/um/os-Linux/drivers/etap.h27
-rw-r--r--arch/um/os-Linux/drivers/ethertap_kern.c119
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c240
-rw-r--r--arch/um/os-Linux/drivers/tuntap.h32
-rw-r--r--arch/um/os-Linux/drivers/tuntap_kern.c104
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c225
-rw-r--r--arch/um/os-Linux/elf_aux.c66
-rw-r--r--arch/um/os-Linux/file.c680
-rw-r--r--arch/um/os-Linux/include/file.h22
-rw-r--r--arch/um/os-Linux/process.c171
-rw-r--r--arch/um/os-Linux/signal.c48
-rw-r--r--arch/um/os-Linux/sys-i386/Makefile10
-rw-r--r--arch/um/os-Linux/sys-i386/registers.c132
-rw-r--r--arch/um/os-Linux/sys-x86_64/Makefile10
-rw-r--r--arch/um/os-Linux/sys-x86_64/registers.c81
-rw-r--r--arch/um/os-Linux/time.c21
-rw-r--r--arch/um/os-Linux/tty.c61
-rw-r--r--arch/um/os-Linux/user_syms.c95
-rw-r--r--arch/um/os-Linux/util/Makefile4
-rw-r--r--arch/um/os-Linux/util/mk_user_constants.c29
22 files changed, 2203 insertions, 0 deletions
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
new file mode 100644
index 00000000000..4ddf540284c
--- /dev/null
+++ b/arch/um/os-Linux/Makefile
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \
+ sys-$(SUBARCH)/
+
+USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
+
+CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile
new file mode 100644
index 00000000000..6c546dc9222
--- /dev/null
+++ b/arch/um/os-Linux/drivers/Makefile
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+ethertap-objs := ethertap_kern.o ethertap_user.o
+tuntap-objs := tuntap_kern.o tuntap_user.o
+
+obj-y =
+obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
+obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
+
+include arch/um/scripts/Makefile.rules
diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h
new file mode 100644
index 00000000000..b84f6c4740f
--- /dev/null
+++ b/arch/um/os-Linux/drivers/etap.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct ethertap_data {
+ char *dev_name;
+ char *gate_addr;
+ int data_fd;
+ int control_fd;
+ void *dev;
+};
+
+extern struct net_user_info ethertap_user_info;
+
+/*
+ * 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 --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
new file mode 100644
index 00000000000..6ae4b19d9f5
--- /dev/null
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "etap.h"
+
+struct ethertap_init {
+ char *dev_name;
+ char *gate_addr;
+};
+
+static void etap_init(struct net_device *dev, void *data)
+{
+ struct uml_net_private *pri;
+ struct ethertap_data *epri;
+ struct ethertap_init *init = data;
+
+ pri = dev->priv;
+ epri = (struct ethertap_data *) pri->user;
+ epri->dev_name = init->dev_name;
+ epri->gate_addr = init->gate_addr;
+ epri->data_fd = -1;
+ epri->control_fd = -1;
+ epri->dev = dev;
+
+ printk("ethertap backend - %s", epri->dev_name);
+ if (epri->gate_addr != NULL)
+ printk(", IP = %s", epri->gate_addr);
+ printk("\n");
+}
+
+static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+ int len;
+
+ *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
+ if(*skb == NULL) return(-ENOMEM);
+ len = net_recvfrom(fd, (*skb)->mac.raw,
+ (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
+ if(len <= 0) return(len);
+ skb_pull(*skb, 2);
+ len -= 2;
+ return(len);
+}
+
+static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+ if(skb_headroom(*skb) < 2){
+ struct sk_buff *skb2;
+
+ skb2 = skb_realloc_headroom(*skb, 2);
+ dev_kfree_skb(*skb);
+ if (skb2 == NULL) return(-ENOMEM);
+ *skb = skb2;
+ }
+ skb_push(*skb, 2);
+ return(net_send(fd, (*skb)->data, (*skb)->len));
+}
+
+struct net_kern_info ethertap_kern_info = {
+ .init = etap_init,
+ .protocol = eth_protocol,
+ .read = etap_read,
+ .write = etap_write,
+};
+
+int ethertap_setup(char *str, char **mac_out, void *data)
+{
+ struct ethertap_init *init = data;
+
+ *init = ((struct ethertap_init)
+ { .dev_name = NULL,
+ .gate_addr = NULL });
+ if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
+ &init->gate_addr))
+ return(0);
+ if(init->dev_name == NULL){
+ printk("ethertap_setup : Missing tap device name\n");
+ return(0);
+ }
+
+ return(1);
+}
+
+static struct transport ethertap_transport = {
+ .list = LIST_HEAD_INIT(ethertap_transport.list),
+ .name = "ethertap",
+ .setup = ethertap_setup,
+ .user = &ethertap_user_info,
+ .kern = &ethertap_kern_info,
+ .private_size = sizeof(struct ethertap_data),
+};
+
+static int register_ethertap(void)
+{
+ register_transport(&ethertap_transport);
+ return(1);
+}
+
+__initcall(register_ethertap);
+
+/*
+ * 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 --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
new file mode 100644
index 00000000000..cd4d6544da7
--- /dev/null
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <net/if.h>
+#include "user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "net_user.h"
+#include "etap.h"
+#include "helper.h"
+#include "os.h"
+
+#define MAX_PACKET ETH_MAX_PACKET
+
+void etap_user_init(void *data, void *dev)
+{
+ struct ethertap_data *pri = data;
+
+ pri->dev = dev;
+}
+
+struct addr_change {
+ enum { ADD_ADDR, DEL_ADDR } what;
+ unsigned char addr[4];
+ unsigned char netmask[4];
+};
+
+static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
+ int fd)
+{
+ struct addr_change change;
+ void *output;
+ int n;
+
+ change.what = op;
+ memcpy(change.addr, addr, sizeof(change.addr));
+ memcpy(change.netmask, netmask, sizeof(change.netmask));
+ n = os_write_file(fd, &change, sizeof(change));
+ if(n != sizeof(change))
+ printk("etap_change - request failed, err = %d\n", -n);
+ output = um_kmalloc(page_size());
+ if(output == NULL)
+ printk("etap_change : Failed to allocate output buffer\n");
+ read_output(fd, output, page_size());
+ if(output != NULL){
+ printk("%s", output);
+ kfree(output);
+ }
+}
+
+static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
+ void *arg)
+{
+ etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
+}
+
+static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
+ void *arg)
+{
+ etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
+}
+
+struct etap_pre_exec_data {
+ int control_remote;
+ int control_me;
+ int data_me;
+};
+
+static void etap_pre_exec(void *arg)
+{
+ struct etap_pre_exec_data *data = arg;
+
+ dup2(data->control_remote, 1);
+ os_close_file(data->data_me);
+ os_close_file(data->control_me);
+}
+
+static int etap_tramp(char *dev, char *gate, int control_me,
+ int control_remote, int data_me, int data_remote)
+{
+ struct etap_pre_exec_data pe_data;
+ int pid, status, err, n;
+ char version_buf[sizeof("nnnnn\0")];
+ char data_fd_buf[sizeof("nnnnnn\0")];
+ char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+ char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
+ data_fd_buf, gate_buf, NULL };
+ char *nosetup_args[] = { "uml_net", version_buf, "ethertap",
+ dev, data_fd_buf, NULL };
+ char **args, c;
+
+ sprintf(data_fd_buf, "%d", data_remote);
+ sprintf(version_buf, "%d", UML_NET_VERSION);
+ if(gate != NULL){
+ strcpy(gate_buf, gate);
+ args = setup_args;
+ }
+ else args = nosetup_args;
+
+ err = 0;
+ pe_data.control_remote = control_remote;
+ pe_data.control_me = control_me;
+ pe_data.data_me = data_me;
+ pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
+
+ if(pid < 0) err = pid;
+ os_close_file(data_remote);
+ os_close_file(control_remote);
+ n = os_read_file(control_me, &c, sizeof(c));
+ if(n != sizeof(c)){
+ printk("etap_tramp : read of status failed, err = %d\n", -n);
+ return(-EINVAL);
+ }
+ if(c != 1){
+ printk("etap_tramp : uml_net failed\n");
+ err = -EINVAL;
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
+ if(n < 0)
+ err = -errno;
+ else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
+ printk("uml_net didn't exit with status 1\n");
+ }
+ return(err);
+}
+
+static int etap_open(void *data)
+{
+ struct ethertap_data *pri = data;
+ char *output;
+ int data_fds[2], control_fds[2], err, output_len;
+
+ err = tap_open_common(pri->dev, pri->gate_addr);
+ if(err) return(err);
+
+ err = os_pipe(data_fds, 0, 0);
+ if(err < 0){
+ printk("data os_pipe failed - err = %d\n", -err);
+ return(err);
+ }
+
+ err = os_pipe(control_fds, 1, 0);
+ if(err < 0){
+ printk("control os_pipe failed - err = %d\n", -err);
+ return(err);
+ }
+
+ err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
+ control_fds[1], data_fds[0], data_fds[1]);
+ output_len = page_size();
+ output = um_kmalloc(output_len);
+ read_output(control_fds[0], output, output_len);
+
+ if(output == NULL)
+ printk("etap_open : failed to allocate output buffer\n");
+ else {
+ printk("%s", output);
+ kfree(output);
+ }
+
+ if(err < 0){
+ printk("etap_tramp failed - err = %d\n", -err);
+ return(err);
+ }
+
+ pri->data_fd = data_fds[0];
+ pri->control_fd = control_fds[0];
+ iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
+ return(data_fds[0]);
+}
+
+static void etap_close(int fd, void *data)
+{
+ struct ethertap_data *pri = data;
+
+ iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
+ os_close_file(fd);
+ os_shutdown_socket(pri->data_fd, 1, 1);
+ os_close_file(pri->data_fd);
+ pri->data_fd = -1;
+ os_close_file(pri->control_fd);
+ pri->control_fd = -1;
+}
+
+static int etap_set_mtu(int mtu, void *data)
+{
+ return(mtu);
+}
+
+static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
+ void *data)
+{
+ struct ethertap_data *pri = data;
+
+ tap_check_ips(pri->gate_addr, addr);
+ if(pri->control_fd == -1) return;
+ etap_open_addr(addr, netmask, &pri->control_fd);
+}
+
+static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
+ void *data)
+{
+ struct ethertap_data *pri = data;
+
+ if(pri->control_fd == -1) return;
+ etap_close_addr(addr, netmask, &pri->control_fd);
+}
+
+struct net_user_info ethertap_user_info = {
+ .init = etap_user_init,
+ .open = etap_open,
+ .close = etap_close,
+ .remove = NULL,
+ .set_mtu = etap_set_mtu,
+ .add_address = etap_add_addr,
+ .delete_address = etap_del_addr,
+ .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP
+};
+
+/*
+ * 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 --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
new file mode 100644
index 00000000000..25d4a286881
--- /dev/null
+++ b/arch/um/os-Linux/drivers/tuntap.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_TUNTAP_H
+#define __UM_TUNTAP_H
+
+#include "net_user.h"
+
+struct tuntap_data {
+ char *dev_name;
+ int fixed_config;
+ char *gate_addr;
+ int fd;
+ void *dev;
+};
+
+extern struct net_user_info tuntap_user_info;
+
+#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 --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
new file mode 100644
index 00000000000..4202b9ebad4
--- /dev/null
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "linux/skbuff.h"
+#include "linux/init.h"
+#include "asm/errno.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "tuntap.h"
+
+struct tuntap_init {
+ char *dev_name;
+ char *gate_addr;
+};
+
+static void tuntap_init(struct net_device *dev, void *data)
+{
+ struct uml_net_private *pri;
+ struct tuntap_data *tpri;
+ struct tuntap_init *init = data;
+
+ pri = dev->priv;
+ tpri = (struct tuntap_data *) pri->user;
+ tpri->dev_name = init->dev_name;
+ tpri->fixed_config = (init->dev_name != NULL);
+ tpri->gate_addr = init->gate_addr;
+ tpri->fd = -1;
+ tpri->dev = dev;
+
+ printk("TUN/TAP backend - ");
+ if (tpri->gate_addr != NULL)
+ printk("IP = %s", tpri->gate_addr);
+ printk("\n");
+}
+
+static int tuntap_read(int fd, struct sk_buff **skb,
+ struct uml_net_private *lp)
+{
+ *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+ if(*skb == NULL) return(-ENOMEM);
+ return(net_read(fd, (*skb)->mac.raw,
+ (*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int tuntap_write(int fd, struct sk_buff **skb,
+ struct uml_net_private *lp)
+{
+ return(net_write(fd, (*skb)->data, (*skb)->len));
+}
+
+struct net_kern_info tuntap_kern_info = {
+ .init = tuntap_init,
+ .protocol = eth_protocol,
+ .read = tuntap_read,
+ .write = tuntap_write,
+};
+
+int tuntap_setup(char *str, char **mac_out, void *data)
+{
+ struct tuntap_init *init = data;
+
+ *init = ((struct tuntap_init)
+ { .dev_name = NULL,
+ .gate_addr = NULL });
+ if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
+ &init->gate_addr))
+ return(0);
+
+ return(1);
+}
+
+static struct transport tuntap_transport = {
+ .list = LIST_HEAD_INIT(tuntap_transport.list),
+ .name = "tuntap",
+ .setup = tuntap_setup,
+ .user = &tuntap_user_info,
+ .kern = &tuntap_kern_info,
+ .private_size = sizeof(struct tuntap_data),
+ .setup_size = sizeof(struct tuntap_init),
+};
+
+static int register_tuntap(void)
+{
+ register_transport(&tuntap_transport);
+ return(1);
+}
+
+__initcall(register_tuntap);
+
+/*
+ * 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 --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
new file mode 100644
index 00000000000..4b83c6c3f48
--- /dev/null
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include "net_user.h"
+#include "tuntap.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "user.h"
+#include "helper.h"
+#include "os.h"
+
+#define MAX_PACKET ETH_MAX_PACKET
+
+void tuntap_user_init(void *data, void *dev)
+{
+ struct tuntap_data *pri = data;
+
+ pri->dev = dev;
+}
+
+static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
+ void *data)
+{
+ struct tuntap_data *pri = data;
+
+ tap_check_ips(pri->gate_addr, addr);
+ if((pri->fd == -1) || pri->fixed_config) return;
+ open_addr(addr, netmask, pri->dev_name);
+}
+
+static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
+ void *data)
+{
+ struct tuntap_data *pri = data;
+
+ if((pri->fd == -1) || pri->fixed_config) return;
+ close_addr(addr, netmask, pri->dev_name);
+}
+
+struct tuntap_pre_exec_data {
+ int stdout;
+ int close_me;
+};
+
+static void tuntap_pre_exec(void *arg)
+{
+ struct tuntap_pre_exec_data *data = arg;
+
+ dup2(data->stdout, 1);
+ os_close_file(data->close_me);
+}
+
+static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
+ char *buffer, int buffer_len, int *used_out)
+{
+ struct tuntap_pre_exec_data data;
+ char version_buf[sizeof("nnnnn\0")];
+ char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
+ NULL };
+ char buf[CMSG_SPACE(sizeof(*fd_out))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ int pid, n;
+
+ sprintf(version_buf, "%d", UML_NET_VERSION);
+
+ data.stdout = remote;
+ data.close_me = me;
+
+ pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
+
+ if(pid < 0) return(-pid);
+
+ os_close_file(remote);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ if(buffer != NULL){
+ iov = ((struct iovec) { buffer, buffer_len });
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ }
+ else {
+ msg.msg_iov = NULL;
+ msg.msg_iovlen = 0;
+ }
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ msg.msg_flags = 0;
+ n = recvmsg(me, &msg, 0);
+ *used_out = n;
+ if(n < 0){
+ printk("tuntap_open_tramp : recvmsg failed - errno = %d\n",
+ errno);
+ return(-errno);
+ }
+ CATCH_EINTR(waitpid(pid, NULL, 0));
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if(cmsg == NULL){
+ printk("tuntap_open_tramp : didn't receive a message\n");
+ return(-EINVAL);
+ }
+ if((cmsg->cmsg_level != SOL_SOCKET) ||
+ (cmsg->cmsg_type != SCM_RIGHTS)){
+ printk("tuntap_open_tramp : didn't receive a descriptor\n");
+ return(-EINVAL);
+ }
+ *fd_out = ((int *) CMSG_DATA(cmsg))[0];
+ return(0);
+}
+
+static int tuntap_open(void *data)
+{
+ struct ifreq ifr;
+ struct tuntap_data *pri = data;
+ char *output, *buffer;
+ int err, fds[2], len, used;
+
+ err = tap_open_common(pri->dev, pri->gate_addr);
+ if(err < 0)
+ return(err);
+
+ if(pri->fixed_config){
+ pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
+ if(pri->fd < 0){
+ printk("Failed to open /dev/net/tun, err = %d\n",
+ -pri->fd);
+ return(pri->fd);
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
+ if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
+ printk("TUNSETIFF failed, errno = %d\n", errno);
+ os_close_file(pri->fd);
+ return(-errno);
+ }
+ }
+ else {
+ err = os_pipe(fds, 0, 0);
+ if(err < 0){
+ printk("tuntap_open : os_pipe failed - err = %d\n",
+ -err);
+ return(err);
+ }
+
+ buffer = get_output_buffer(&len);
+ if(buffer != NULL) len--;
+ used = 0;
+
+ err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
+ fds[1], buffer, len, &used);
+
+ output = buffer;
+ if(err < 0) {
+ printk("%s", output);
+ free_output_buffer(buffer);
+ printk("tuntap_open_tramp failed - err = %d\n", -err);
+ return(err);
+ }
+
+ pri->dev_name = uml_strdup(buffer);
+ output += IFNAMSIZ;
+ printk("%s", output);
+ free_output_buffer(buffer);
+
+ os_close_file(fds[0]);
+ iter_addresses(pri->dev, open_addr, pri->dev_name);
+ }
+
+ return(pri->fd);
+}
+
+static void tuntap_close(int fd, void *data)
+{
+ struct tuntap_data *pri = data;
+
+ if(!pri->fixed_config)
+ iter_addresses(pri->dev, close_addr, pri->dev_name);
+ os_close_file(fd);
+ pri->fd = -1;
+}
+
+static int tuntap_set_mtu(int mtu, void *data)
+{
+ return(mtu);
+}
+
+struct net_user_info tuntap_user_info = {
+ .init = tuntap_user_init,
+ .open = tuntap_open,
+ .close = tuntap_close,
+ .remove = NULL,
+ .set_mtu = tuntap_set_mtu,
+ .add_address = tuntap_add_addr,
+ .delete_address = tuntap_del_addr,
+ .max_packet = MAX_PACKET
+};
+
+/*
+ * 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 --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
new file mode 100644
index 00000000000..9aee0b62ebc
--- /dev/null
+++ b/arch/um/os-Linux/elf_aux.c
@@ -0,0 +1,66 @@
+/*
+ * arch/um/kernel/elf_aux.c
+ *
+ * Scan the Elf auxiliary vector provided by the host to extract
+ * information about vsyscall-page, etc.
+ *
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com)
+ */
+#include <elf.h>
+#include <stddef.h>
+#include "init.h"
+#include "elf_user.h"
+
+#if ELF_CLASS == ELFCLASS32
+typedef Elf32_auxv_t elf_auxv_t;
+#else
+typedef Elf64_auxv_t elf_auxv_t;
+#endif
+
+char * elf_aux_platform;
+long elf_aux_hwcap;
+
+unsigned long vsyscall_ehdr;
+unsigned long vsyscall_end;
+
+unsigned long __kernel_vsyscall;
+
+__init void scan_elf_aux( char **envp)
+{
+ long page_size = 0;
+ elf_auxv_t * auxv;
+
+ while ( *envp++ != NULL) ;
+
+ for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
+ switch ( auxv->a_type ) {
+ case AT_SYSINFO:
+ __kernel_vsyscall = auxv->a_un.a_val;
+ break;
+ case AT_SYSINFO_EHDR:
+ vsyscall_ehdr = auxv->a_un.a_val;
+ break;
+ case AT_HWCAP:
+ elf_aux_hwcap = auxv->a_un.a_val;
+ break;
+ case AT_PLATFORM:
+ elf_aux_platform = auxv->a_un.a_ptr;
+ break;
+ case AT_PAGESZ:
+ page_size = auxv->a_un.a_val;
+ break;
+ }
+ }
+ if ( ! __kernel_vsyscall || ! vsyscall_ehdr ||
+ ! elf_aux_hwcap || ! elf_aux_platform ||
+ ! page_size || (vsyscall_ehdr % page_size) ) {
+ __kernel_vsyscall = 0;
+ vsyscall_ehdr = 0;
+ elf_aux_hwcap = 0;
+ elf_aux_platform = "i586";
+ }
+ else {
+ vsyscall_end = vsyscall_ehdr + page_size;
+ }
+}
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
new file mode 100644
index 00000000000..77d4066d1af
--- /dev/null
+++ b/arch/um/os-Linux/file.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include "os.h"
+#include "user.h"
+#include "kern_util.h"
+
+static void copy_stat(struct uml_stat *dst, struct stat64 *src)
+{
+ *dst = ((struct uml_stat) {
+ .ust_dev = src->st_dev, /* device */
+ .ust_ino = src->st_ino, /* inode */
+ .ust_mode = src->st_mode, /* protection */
+ .ust_nlink = src->st_nlink, /* number of hard links */
+ .ust_uid = src->st_uid, /* user ID of owner */
+ .ust_gid = src->st_gid, /* group ID of owner */
+ .ust_size = src->st_size, /* total size, in bytes */
+ .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
+ .ust_blocks = src->st_blocks, /* number of blocks allocated */
+ .ust_atime = src->st_atime, /* time of last access */
+ .ust_mtime = src->st_mtime, /* time of last modification */
+ .ust_ctime = src->st_ctime, /* time of last change */
+ });
+}
+
+int os_stat_fd(const int fd, struct uml_stat *ubuf)
+{
+ struct stat64 sbuf;
+ int err;
+
+ do {
+ err = fstat64(fd, &sbuf);
+ } while((err < 0) && (errno == EINTR)) ;
+
+ if(err < 0)
+ return(-errno);
+
+ if(ubuf != NULL)
+ copy_stat(ubuf, &sbuf);
+ return(err);
+}
+
+int os_stat_file(const char *file_name, struct uml_stat *ubuf)
+{
+ struct stat64 sbuf;
+ int err;
+
+ do {
+ err = stat64(file_name, &sbuf);
+ } while((err < 0) && (errno == EINTR)) ;
+
+ if(err < 0)
+ return(-errno);
+
+ if(ubuf != NULL)
+ copy_stat(ubuf, &sbuf);
+ return(err);
+}
+
+int os_access(const char* file, int mode)
+{
+ int amode, err;
+
+ amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
+ (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
+
+ err = access(file, amode);
+ if(err < 0)
+ return(-errno);
+
+ return(0);
+}
+
+void os_print_error(int error, const char* str)
+{
+ errno = error < 0 ? -error : error;
+
+ perror(str);
+}
+
+/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
+int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
+{
+ int err;
+
+ err = ioctl(fd, cmd, arg);
+ if(err < 0)
+ return(-errno);
+
+ return(err);
+}
+
+int os_window_size(int fd, int *rows, int *cols)
+{
+ struct winsize size;
+
+ if(ioctl(fd, TIOCGWINSZ, &size) < 0)
+ return(-errno);
+
+ *rows = size.ws_row;
+ *cols = size.ws_col;
+
+ return(0);
+}
+
+int os_new_tty_pgrp(int fd, int pid)
+{
+ if(ioctl(fd, TIOCSCTTY, 0) < 0){
+ printk("TIOCSCTTY failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ if(tcsetpgrp(fd, pid) < 0){
+ printk("tcsetpgrp failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ return(0);
+}
+
+/* FIXME: ensure namebuf in os_get_if_name is big enough */
+int os_get_ifname(int fd, char* namebuf)
+{