Commit 1cded551 authored by Paolo \'Blaisorblade\' Giarrusso's avatar Paolo \'Blaisorblade\' Giarrusso Committed by Linus Torvalds

[PATCH] uml: Uml base patch

The main part of UML; it is the last distributed patch for 2.6.7 Removes skas
support from the main UML patch; apply or get conflicts.
Signed-off-by: default avatarPaolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
Cc: Jeff Dike <jdike@addtoit.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 27ef71dc
...@@ -61,6 +61,20 @@ config MODE_SKAS ...@@ -61,6 +61,20 @@ config MODE_SKAS
config NET config NET
bool "Networking support" bool "Networking support"
help
Unless you really know what you are doing, you should say Y here.
The reason is that some programs need kernel networking support even
when running on a stand-alone machine that isn't connected to any
other computer. If you are upgrading from an older kernel, you
should consider updating your networking tools too because changes
in the kernel and the tools often go hand in hand. The tools are
contained in the package net-tools, the location and version number
of which are given in Documentation/Changes.
For a general introduction to Linux networking, it is highly
recommended to read the NET-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
source "fs/Kconfig.binfmt" source "fs/Kconfig.binfmt"
...@@ -85,6 +99,19 @@ config HOSTFS ...@@ -85,6 +99,19 @@ config HOSTFS
If you'd like to be able to work with files stored on the host, If you'd like to be able to work with files stored on the host,
say Y or M here; otherwise say N. say Y or M here; otherwise say N.
config HPPFS
tristate "HoneyPot ProcFS"
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
Its purpose is to allow a UML to appear to be a physical machine
by removing or changing anything in /proc which gives away the
identity of a UML.
See http://user-mode-linux.sf.net/hppfs.html for more information.
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
config MCONSOLE config MCONSOLE
bool "Management console" bool "Management console"
...@@ -164,6 +191,17 @@ config KERNEL_STACK_ORDER ...@@ -164,6 +191,17 @@ config KERNEL_STACK_ORDER
be 1 << order pages. The default is OK unless you're running Valgrind be 1 << order pages. The default is OK unless you're running Valgrind
on UML, in which case, set this to 3. on UML, in which case, set this to 3.
config UML_REAL_TIME_CLOCK
bool "Real-time Clock"
default y
help
This option makes UML time deltas match wall clock deltas. This should
normally be enabled. The exception would be if you are debugging with
UML and spend long times with UML stopped at a breakpoint. In this
case, when UML is restarted, it will call the timer enough times to make
up for the time spent at the breakpoint. This could result in a
noticable lag. If this is a problem, then disable this option.
endmenu endmenu
source "init/Kconfig" source "init/Kconfig"
......
...@@ -9,6 +9,10 @@ config FRAME_POINTER ...@@ -9,6 +9,10 @@ config FRAME_POINTER
config PT_PROXY config PT_PROXY
bool "Enable ptrace proxy" bool "Enable ptrace proxy"
depends on XTERM_CHAN && DEBUG_INFO depends on XTERM_CHAN && DEBUG_INFO
help
This option enables a debugging interface which allows gdb to debug
the kernel without needing to actually attach to kernel threads.
If you want to do kernel debugging, say Y here; otherwise say N.
config GPROF config GPROF
bool "Enable gprof support" bool "Enable gprof support"
......
...@@ -29,6 +29,20 @@ config BLK_DEV_UBD_SYNC ...@@ -29,6 +29,20 @@ config BLK_DEV_UBD_SYNC
wise choice too. In all other cases (for example, if you're just wise choice too. In all other cases (for example, if you're just
playing around with User-Mode Linux) you can choose N. playing around with User-Mode Linux) you can choose N.
# Turn this back on when the driver actually works
#
#config BLK_DEV_COW
# tristate "COW block device"
# help
# This is a layered driver which sits above two other block devices.
# One is read-only, and the other is a read-write layer which stores
# all changes. This provides the illusion that the read-only layer
# can be mounted read-write and changed.
config BLK_DEV_COW_COMMON
bool
default BLK_DEV_COW || BLK_DEV_UBD
config BLK_DEV_LOOP config BLK_DEV_LOOP
tristate "Loopback device support" tristate "Loopback device support"
......
menu "Network Devices" menu "UML Network Devices"
depends on NET depends on NET
# UML virtual driver # UML virtual driver
...@@ -176,73 +176,5 @@ config UML_NET_SLIRP ...@@ -176,73 +176,5 @@ config UML_NET_SLIRP
Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
# Below are hardware-independent drivers mirrored from
# drivers/net/Config.in. It would be nice if Linux
# had HW independent drivers separated from the other
# but it does not. Until then each non-ISA/PCI arch
# needs to provide it's own menu of network drivers
config DUMMY
tristate "Dummy net driver support"
config BONDING
tristate "Bonding driver support"
config EQUALIZER
tristate "EQL (serial line load balancing) support"
config TUN
tristate "Universal TUN/TAP device driver support"
config ETHERTAP
tristate "Ethertap network tap (OBSOLETE)"
depends on EXPERIMENTAL && NETLINK
config PPP
tristate "PPP (point-to-point protocol) support"
config PPP_MULTILINK
bool "PPP multilink support (EXPERIMENTAL)"
depends on PPP && EXPERIMENTAL
config PPP_FILTER
bool "PPP filtering"
depends on PPP && FILTER
config PPP_ASYNC
tristate "PPP support for async serial ports"
depends on PPP
config PPP_SYNC_TTY
tristate "PPP support for sync tty ports"
depends on PPP
config PPP_DEFLATE
tristate "PPP Deflate compression"
depends on PPP
config PPP_BSDCOMP
tristate "PPP BSD-Compress compression"
depends on PPP
config PPPOE
tristate "PPP over Ethernet (EXPERIMENTAL)"
depends on PPP && EXPERIMENTAL
config SLIP
tristate "SLIP (serial line) support"
config SLIP_COMPRESSED
bool "CSLIP compressed headers"
depends on SLIP=y
config SLIP_SMART
bool "Keepalive and linefill"
depends on SLIP=y
config SLIP_MODE_SLIP6
bool "Six bit SLIP encapsulation"
depends on SLIP=y
endmenu endmenu
...@@ -22,17 +22,21 @@ core-y += $(ARCH_DIR)/kernel/ \ ...@@ -22,17 +22,21 @@ core-y += $(ARCH_DIR)/kernel/ \
$(ARCH_DIR)/sys-$(SUBARCH)/ $(ARCH_DIR)/sys-$(SUBARCH)/
# Have to precede the include because the included Makefiles reference them. # Have to precede the include because the included Makefiles reference them.
SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \
include/asm-um/sigcontext.h include/asm-um/processor.h \ arch-signal.h module.h
include/asm-um/ptrace.h include/asm-um/arch-signal.h SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
include $(ARCH_DIR)/Makefile-$(SUBARCH) # This target adds dependencies to "prepare". They are defined in the included
include $(ARCH_DIR)/Makefile-os-$(OS) # Makefiles (see Makefile-i386).
.PHONY: sys_prepare
sys_prepare:
@:
MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt
MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas
...@@ -41,6 +45,9 @@ ifneq ($(MAKEFILE-y),) ...@@ -41,6 +45,9 @@ ifneq ($(MAKEFILE-y),)
include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y))
endif endif
include $(ARCH_DIR)/Makefile-$(SUBARCH)
include $(ARCH_DIR)/Makefile-os-$(OS)
EXTRAVERSION := $(EXTRAVERSION)-1um EXTRAVERSION := $(EXTRAVERSION)-1um
ARCH_INCLUDE = -I$(ARCH_DIR)/include ARCH_INCLUDE = -I$(ARCH_DIR)/include
...@@ -52,14 +59,20 @@ ARCH_INCLUDE = -I$(ARCH_DIR)/include ...@@ -52,14 +59,20 @@ ARCH_INCLUDE = -I$(ARCH_DIR)/include
CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
-D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
$(MODE_INCLUDE) -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE)
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
# These are needed for clean and mrproper, since in that case .config is not
# included; the values here are meaningless
CONFIG_NEST_LEVEL ?= 0
CONFIG_KERNEL_HALF_GIGS ?= 0
SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
ifeq ($(CONFIG_MODE_SKAS), y) ifeq ($(CONFIG_MODE_SKAS), y)
$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h $(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
endif endif
include/linux/version.h: arch/$(ARCH)/Makefile include/linux/version.h: arch/$(ARCH)/Makefile
...@@ -98,17 +111,17 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT) ...@@ -98,17 +111,17 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT)
CONFIG_KERNEL_STACK_ORDER ?= 2 CONFIG_KERNEL_STACK_ORDER ?= 2
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \ CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \
-DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
-DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \
-DKERNEL_STACK_SIZE=$(STACK_SIZE) -DKERNEL_STACK_SIZE=$(STACK_SIZE))
CPPFLAGS_$(LD_SCRIPT-y) = $(CPPFLAGS_vmlinux.lds) -P -C -Uum export CPPFLAGS_$(LD_SCRIPT-y) = $(CPPFLAGS_vmlinux.lds) -P -C -Uum
LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y)
$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE #$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE
$(call if_changed_dep,as_s_S) # $(call if_changed_dep,as_s_S)
linux: vmlinux $(LD_SCRIPT-y) linux: vmlinux $(LD_SCRIPT-y)
$(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \
...@@ -116,37 +129,47 @@ linux: vmlinux $(LD_SCRIPT-y) ...@@ -116,37 +129,47 @@ linux: vmlinux $(LD_SCRIPT-y)
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS))
USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
$(MODE_INCLUDE) $(MODE_INCLUDE)
# To get a definition of F_SETSIG # To get a definition of F_SETSIG
USER_CFLAGS += -D_GNU_SOURCE USER_CFLAGS += -D_GNU_SOURCE
# From main Makefile, these options are set after including the ARCH makefile.
# So copy them here.
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
USER_CFLAGS += -Os
else
USER_CFLAGS += -O2
endif
ifndef CONFIG_FRAME_POINTER
USER_CFLAGS += -fomit-frame-pointer
endif
ifdef CONFIG_DEBUG_INFO
USER_CFLAGS += -g
endif
CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds \ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds \
$(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS) $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \
$(GEN_HEADERS)
$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c sys_prepare
@ echo ' MAIN $@'
@ $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
archmrproper: archmrproper:
for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ @:
do \
$(MAKE) -C $$d archmrproper; \
done
rm -f $(CLEAN_FILES) $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
archclean: sysclean
for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
do \
$(MAKE) -C $$d clean; \
done
find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
-o -name '*.gcov' \) -type f -print | xargs rm -f
rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
archdep: archclean:
for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
-o -name '*.gcov' \) -type f -print | xargs rm -f
$(SYMLINK_HEADERS): $(SYMLINK_HEADERS):
cd $(TOPDIR)/$(dir $@) ; \ cd $(TOPDIR)/$(dir $@) ; \
...@@ -161,19 +184,26 @@ $(ARCH_DIR)/include/sysdep: ...@@ -161,19 +184,26 @@ $(ARCH_DIR)/include/sysdep:
$(ARCH_DIR)/os: $(ARCH_DIR)/os:
cd $(ARCH_DIR) && ln -sf os-$(OS) os cd $(ARCH_DIR) && ln -sf os-$(OS) os
$(ARCH_DIR)/include/uml-config.h : # Generated files
sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ define filechk_umlconfig
sed 's/ CONFIG/ UML_CONFIG/'
endef
$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h
$(call filechk,umlconfig)
filechk_gen_header = $<
$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
$< > $@ $(call filechk,gen_header)
$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants $(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
$< > $@ $(call filechk,gen_header)
$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ $(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \
$(ARCH_DIR)/util FORCE ; sys_prepare FORCE ;
$(ARCH_DIR)/util: FORCE $(ARCH_DIR)/util: FORCE
@$(call descend,$@,) $(Q)$(MAKE) $(build)=$@
export SUBARCH USER_CFLAGS OS export SUBARCH USER_CFLAGS OS
...@@ -16,22 +16,27 @@ SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util ...@@ -16,22 +16,27 @@ SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util
SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
sys_prepare: $(SYS_DIR)/sc.h
prepare: $(SYS_HEADERS) prepare: $(SYS_HEADERS)
filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc
$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
$< > $@ $(call filechk,$@)
filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread
$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
$< > $@ $(call filechk,$@)
$(SYS_UTIL_DIR)/mk_sc: FORCE ; $(SYS_UTIL_DIR)/mk_sc: scripts/basic/fixdep include/config/MARKER FORCE ;
@$(call descend,$(SYS_UTIL_DIR),$@) $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; $(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ;
@$(call descend,$(SYS_UTIL_DIR),$@) $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
$(SYS_UTIL_DIR): include/asm FORCE $(SYS_UTIL_DIR): include/asm FORCE
@$(call descend,$@,) $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR)
sysclean : CLEAN_FILES += $(SYS_HEADERS)
rm -f $(SYS_HEADERS)
...@@ -14,7 +14,7 @@ MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include ...@@ -14,7 +14,7 @@ MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include
LINK_SKAS = -Wl,-rpath,/lib LINK_SKAS = -Wl,-rpath,/lib
LD_SCRIPT_SKAS = dyn.lds LD_SCRIPT_SKAS = dyn.lds
GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h :
$(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h $(Q)$(MAKE) $(build)=$(ARCH_DIR)/kernel/skas $@
...@@ -227,7 +227,6 @@ CONFIG_ROMFS_FS=m ...@@ -227,7 +227,6 @@ CONFIG_ROMFS_FS=m
CONFIG_EXT2_FS=y CONFIG_EXT2_FS=y
CONFIG_SYSV_FS=m CONFIG_SYSV_FS=m
CONFIG_UDF_FS=m CONFIG_UDF_FS=m
# CONFIG_UDF_RW is not set
CONFIG_UFS_FS=m CONFIG_UFS_FS=m
# CONFIG_UFS_FS_WRITE is not set # CONFIG_UFS_FS_WRITE is not set
......
...@@ -3,29 +3,19 @@ ...@@ -3,29 +3,19 @@
# #
CONFIG_USERMODE=y CONFIG_USERMODE=y
CONFIG_MMU=y CONFIG_MMU=y
CONFIG_SWAP=y
CONFIG_UID16=y CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_CONFIG_LOG_BUF_SHIFT=14
# #
# Code maturity level options # UML-specific options
#
CONFIG_EXPERIMENTAL=y
#
# General Setup
# #
CONFIG_MODE_TT=y CONFIG_MODE_TT=y
CONFIG_MODE_SKAS=y CONFIG_MODE_SKAS=y
CONFIG_NET=y CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y CONFIG_BINFMT_MISC=y
CONFIG_HOSTFS=y CONFIG_HOSTFS=y
CONFIG_HPPFS=y
CONFIG_MCONSOLE=y CONFIG_MCONSOLE=y
CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ=y
# CONFIG_HOST_2G_2G is not set # CONFIG_HOST_2G_2G is not set
...@@ -36,12 +26,43 @@ CONFIG_KERNEL_HALF_GIGS=1 ...@@ -36,12 +26,43 @@ CONFIG_KERNEL_HALF_GIGS=1
# CONFIG_HIGHMEM is not set # CONFIG_HIGHMEM is not set
CONFIG_PROC_MM=y CONFIG_PROC_MM=y
CONFIG_KERNEL_STACK_ORDER=2 CONFIG_KERNEL_STACK_ORDER=2
CONFIG_UML_REAL_TIME_CLOCK=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_STANDALONE=y
CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSCTL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# #
# Loadable module support # Loadable module support
# #
CONFIG_MODULES=y # CONFIG_MODULES is not set
# CONFIG_KMOD is not set
#
# Generic Driver Options
#
# #
# Character Devices # Character Devices
...@@ -69,6 +90,7 @@ CONFIG_HOSTAUDIO=y ...@@ -69,6 +90,7 @@ CONFIG_HOSTAUDIO=y
# #
CONFIG_BLK_DEV_UBD=y CONFIG_BLK_DEV_UBD=y
# CONFIG_BLK_DEV_UBD_SYNC is not set # CONFIG_BLK_DEV_UBD_SYNC is not set
CONFIG_BLK_DEV_COW_COMMON=y
CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM=y
...@@ -78,7 +100,7 @@ CONFIG_BLK_DEV_INITRD=y ...@@ -78,7 +100,7 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_NETDEVICES=y CONFIG_NETDEVICES=y
# #
# Network Devices # UML Network Devices
# #
CONFIG_UML_NET=y CONFIG_UML_NET=y
CONFIG_UML_NET_ETHERTAP=y CONFIG_UML_NET_ETHERTAP=y
...@@ -88,22 +110,6 @@ CONFIG_UML_NET_DAEMON=y ...@@ -88,22 +110,6 @@ CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_MCAST=y CONFIG_UML_NET_MCAST=y
# CONFIG_UML_NET_PCAP is not set # CONFIG_UML_NET_PCAP is not set
CONFIG_UML_NET_SLIRP=y CONFIG_UML_NET_SLIRP=y
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=y
# CONFIG_ETHERTAP is not set
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPPOE is not set
CONFIG_SLIP=y
# CONFIG_SLIP_COMPRESSED is not set
# CONFIG_SLIP_SMART is not set
# CONFIG_SLIP_MODE_SLIP6 is not set
# #
# Networking support # Networking support
...@@ -115,8 +121,6 @@ CONFIG_SLIP=y ...@@ -115,8 +121,6 @@ CONFIG_SLIP=y
CONFIG_PACKET=y CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y CONFIG_PACKET_MMAP=y
# CONFIG_NETLINK_DEV is not set # CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y CONFIG_UNIX=y
# CONFIG_NET_KEY is not set # CONFIG_NET_KEY is not set
CONFIG_INET=y CONFIG_INET=y
...@@ -130,8 +134,11 @@ CONFIG_INET=y ...@@ -130,8 +134,11 @@ CONFIG_INET=y
# CONFIG_SYN_COOKIES is not set # CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set # CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set # CONFIG_INET_ESP is not set
# CONFIG_XFRM_USER is not set # CONFIG_INET_IPCOMP is not set
# CONFIG_IPV6 is not set # CONFIG_IPV6 is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_NETFILTER is not set
# #
# SCTP Configuration (EXPERIMENTAL) # SCTP Configuration (EXPERIMENTAL)
...@@ -140,9 +147,9 @@ CONFIG_IPV6_SCTP__=y ...@@ -140,9 +147,9 @@ CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set # CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set # CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set # CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set # CONFIG_LLC2 is not set
# CONFIG_DECNET is not set # CONFIG_IPX is not set
# CONFIG_BRIDGE is not set # CONFIG_ATALK is not set
# CONFIG_X25 is not set # CONFIG_X25 is not set
# CONFIG_LAPB is not set # CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set # CONFIG_NET_DIVERT is not set
...@@ -159,6 +166,10 @@ CONFIG_IPV6_SCTP__=y ...@@ -159,6 +166,10 @@ CONFIG_IPV6_SCTP__=y
# Network testing # Network testing
# #
# CONFIG_NET_PKTGEN is not set # CONFIG_NET_PKTGEN is not set
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=y
# #
# Ethernet (10 or 100Mbit) # Ethernet (10 or 100Mbit)
...@@ -169,13 +180,29 @@ CONFIG_IPV6_SCTP__=y ...@@ -169,13 +180,29 @@ CONFIG_IPV6_SCTP__=y
# Ethernet (1000 Mbit) # Ethernet (1000 Mbit)
# #
#
# Ethernet (10000 Mbit)
#
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_FILTER is not set
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPPOE is not set
CONFIG_SLIP=y
# CONFIG_SLIP_COMPRESSED is not set
# CONFIG_SLIP_SMART is not set
# CONFIG_SLIP_MODE_SLIP6 is not set
# #
# Wireless LAN (non-hamradio) # Wireless LAN (non-hamradio)
# #
# CONFIG_NET_RADIO is not set # CONFIG_NET_RADIO is not set
# #
# Token Ring devices (depends on LLC=y) # Token Ring devices
# #
# CONFIG_SHAPER is not set # CONFIG_SHAPER is not set
...@@ -184,69 +211,101 @@ CONFIG_IPV6_SCTP__=y ...@@ -184,69 +211,101 @@ CONFIG_IPV6_SCTP__=y
# #
# CONFIG_WAN is not set # CONFIG_WAN is not set
#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
#
# IrDA (infrared) support
#
# CONFIG_IRDA is not set
#
# Bluetooth support
#
# CONFIG_BT is not set
# #
# File systems # File systems
# #
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
CONFIG_MINIX_FS=y
# CONFIG_ROMFS_FS is not set
CONFIG_QUOTA=y CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set # CONFIG_QFMT_V2 is not set
CONFIG_QUOTACTL=y CONFIG_QUOTACTL=y
CONFIG_AUTOFS_FS=m CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=m CONFIG_AUTOFS4_FS=y
CONFIG_REISERFS_FS=m
# CONFIG_REISERFS_CHECK is not set #
# CONFIG_REISERFS_PROC_INFO is not set # CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_ZISOFS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_DEVFS_FS=y
CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set # CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set # CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set # CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set # CONFIG_BFS_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
# CONFIG_EFS_FS is not set # CONFIG_EFS_FS is not set
CONFIG_JFFS_FS=y CONFIG_JFFS_FS=y
CONFIG_JFFS_FS_VERBOSE=0 CONFIG_JFFS_FS_VERBOSE=0
CONFIG_JFFS_PROC_FS=y
# CONFIG_JFFS2_FS is not set # CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set # CONFIG_CRAMFS is not set
# CONFIG_TMPFS is not set
CONFIG_RAMFS=y
CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
# CONFIG_ZISOFS is not set
# CONFIG_JFS_FS is not set
CONFIG_MINIX_FS=m
# CONFIG_VXFS_FS is not set # CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set # CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
CONFIG_DEVFS_FS=y
CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_SYSV_FS is not set # CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set # CONFIG_UFS_FS is not set
# CONFIG_XFS_FS is not set
# #
# Network File Systems # Network File Systems
# #
# CONFIG_CODA_FS is not set
# CONFIG_INTERMEZZO_FS is not set
# CONFIG_NFS_FS is not set # CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set # CONFIG_NFSD is not set
# CONFIG_EXPORTFS is not set # CONFIG_EXPORTFS is not set
# CONFIG_CIFS is not set
# CONFIG_SMB_FS is not set # CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set # CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set # CONFIG_AFS_FS is not set
# #
...@@ -254,11 +313,11 @@ CONFIG_EXT2_FS=y ...@@ -254,11 +313,11 @@ CONFIG_EXT2_FS=y
# #
# CONFIG_PARTITION_ADVANCED is not set # CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y CONFIG_MSDOS_PARTITION=y
CONFIG_NLS=y
# #
# Native Language Support # Native Language Support
# #
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_437 is not set
# CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_737 is not set
...@@ -316,28 +375,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" ...@@ -316,28 +375,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# #
# SCSI support # SCSI support
# #
CONFIG_SCSI=y # CONFIG_SCSI is not set
CONFIG_GENERIC_ISA_DMA=y
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SR_EXTRA_DEVS=2
CONFIG_CHR_DEV_SG=y
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
CONFIG_SCSI_DEBUG_QUEUES=y
CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_DEBUG=y
# #
# Multi-device support (RAID and LVM) # Multi-device support (RAID and LVM)
...@@ -359,6 +397,7 @@ CONFIG_MTD_CHAR=y ...@@ -359,6 +397,7 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set # CONFIG_FTL is not set
# CONFIG_NFTL is not set # CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# #
# RAM/ROM/Flash chip drivers # RAM/ROM/Flash chip drivers
...@@ -373,20 +412,21 @@ CONFIG_MTD_BLOCK=y ...@@ -373,20 +412,21 @@ CONFIG_MTD_BLOCK=y
# #
# Mapping drivers for chip access # Mapping drivers for chip access
# #
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# #
# Self-contained MTD device drivers # Self-contained MTD device drivers
# #
# CONFIG_MTD_SLRAM is not set # CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_MTDRAM is not set
CONFIG_MTD_BLKMTD=m CONFIG_MTD_BLKMTD=y
# #
# Disk-On-Chip Device Drivers # Disk-On-Chip Device Drivers
# #
# CONFIG_MTD_DOC1000 is not set
# CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
# #
# NAND Flash Device Drivers # NAND Flash Device Drivers
......
# #
# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) # Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL # Licensed under the GPL
# #
...@@ -39,6 +39,8 @@ obj-$(CONFIG_PTY_CHAN) += pty.o ...@@ -39,6 +39,8 @@ obj-$(CONFIG_PTY_CHAN) += pty.o
obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_TTY_CHAN) += tty.o
obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
obj-$(CONFIG_UML_WATCHDOG) += harddog.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o
obj-$(CONFIG_BLK_DEV_COW) += cow_kern.o
obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
obj-y += stdio_console.o $(CHAN_OBJS) obj-y += stdio_console.o $(CHAN_OBJS)
...@@ -46,18 +48,7 @@ USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) ...@@ -46,18 +48,7 @@ USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
null.o pty.o tty.o xterm.o null.o pty.o tty.o xterm.o
USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c $(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
clean:
modules:
fastdep:
dep:
archmrproper: clean
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/string.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <asm/irq.h> #include <asm/irq.h>
#include "chan_kern.h" #include "chan_kern.h"
...@@ -265,6 +266,11 @@ static int one_chan_config_string(struct chan *chan, char *str, int size, ...@@ -265,6 +266,11 @@ static int one_chan_config_string(struct chan *chan, char *str, int size,
{ {
int n = 0; int n = 0;
if(chan == NULL){
CONFIG_CHUNK(str, size, n, "none", 1);
return(n);
}
CONFIG_CHUNK(str, size, n, chan->ops->type, 0); CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
if(chan->dev == NULL){ if(chan->dev == NULL){
...@@ -420,7 +426,8 @@ int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, ...@@ -420,7 +426,8 @@ int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
INIT_LIST_HEAD(chans); INIT_LIST_HEAD(chans);
} }
if((out = strchr(str, ',')) != NULL){ out = strchr(str, ',');
if(out != NULL){
in = str; in = str;
*out = '\0'; *out = '\0';
out++; out++;
...@@ -475,12 +482,15 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task, ...@@ -475,12 +482,15 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
goto out; goto out;
} }
err = chan->ops->read(chan->fd, &c, chan->data); err = chan->ops->read(chan->fd, &c, chan->data);
if(err > 0) tty_receive_char(tty, c); if(err > 0)
tty_receive_char(tty, c);
} while(err > 0); } while(err > 0);
if(err == 0) reactivate_fd(chan->fd, irq); if(err == 0) reactivate_fd(chan->fd, irq);
if(err == -EIO){ if(err == -EIO){
if(chan->primary){ if(chan->primary){
if(tty != NULL) tty_hangup(tty); if(tty != NULL)
tty_hangup(tty);
line_disable(dev, irq); line_disable(dev, irq);
close_chan(chans); close_chan(chans);
free_chan(chans); free_chan(chans);
......
/* /*
* Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <termios.h> #include <termios.h>
#include <fcntl.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <sys/stat.h> #include <sys/stat.h>
...@@ -24,29 +23,27 @@ ...@@ -24,29 +23,27 @@
void generic_close(int fd, void *unused) void generic_close(int fd, void *unused)
{ {
close(fd); os_close_file(fd);
} }
int generic_read(int fd, char *c_out, void *unused) int generic_read(int fd, char *c_out, void *unused)
{ {
int n; int n;
n = read(fd, c_out, sizeof(*c_out)); n = os_read_file(fd, c_out, sizeof(*c_out));
if(n < 0){
if(errno == EAGAIN) return(0); if(n == -EAGAIN)
return(-errno); return(0);
} else if(n == 0)
else if(n == 0) return(-EIO); return(-EIO);
return(1); return(n);
} }
/* XXX Trivial wrapper around os_write_file */
int generic_write(int fd, const char *buf, int n, void *unused) int generic_write(int fd, const char *buf, int n, void *unused)
{ {
int count; return(os_write_file(fd, buf, n));
count = write(fd, buf, n);
if(count < 0) return(-errno);
return(count);
} }
int generic_console_write(int fd, const char *buf, int n, void *unused) int generic_console_write(int fd, const char *buf, int n, void *unused)
...@@ -68,15 +65,18 @@ int generic_console_write(int fd, const char *buf, int n, void *unused) ...@@ -68,15 +65,18 @@ int generic_console_write(int fd, const char *buf, int n, void *unused)
int generic_window_size(int fd, void *unused, unsigned short *rows_out, int generic_window_size(int fd, void *unused, unsigned short *rows_out,
unsigned short *cols_out) unsigned short *cols_out)
{ {
struct winsize size; int rows, cols;
int ret = 0; int ret;
if(ioctl(fd, TIOCGWINSZ, &size) == 0){ ret = os_window_size(fd, &rows, &cols);
ret = ((*rows_out != size.ws_row) || if(ret < 0)
(*cols_out != size.ws_col)); return(ret);
*rows_out = size.ws_row;
*cols_out = size.ws_col; ret = ((*rows_out != rows) || (*cols_out != cols));
}
*rows_out = rows;
*cols_out = cols;
return(ret); return(ret);
} }
...@@ -100,14 +100,16 @@ static int winch_thread(void *arg) ...@@ -100,14 +100,16 @@ static int winch_thread(void *arg)
struct winch_data *data = arg; struct winch_data *data = arg;
sigset_t sigs; sigset_t sigs;
int pty_fd, pipe_fd; int pty_fd, pipe_fd;
int count, err;
char c = 1; char c = 1;
close(data->close_me); os_close_file(data->close_me);
pty_fd = data->pty_fd; pty_fd = data->pty_fd;
pipe_fd = data->pipe_fd; pipe_fd = data->pipe_fd;
if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)) count = os_write_file(pipe_fd, &c, sizeof(c));
if(count != sizeof(c))
printk("winch_thread : failed to write synchronization " printk("winch_thread : failed to write synchronization "
"byte, errno = %d\n", errno); "byte, err = %d\n", -count);
signal(SIGWINCH, winch_handler); signal(SIGWINCH, winch_handler);
sigfillset(&sigs); sigfillset(&sigs);
...@@ -123,26 +125,24 @@ static int winch_thread(void *arg) ...@@ -123,26 +125,24 @@ static int winch_thread(void *arg)
exit(1); exit(1);
} }
if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){ err = os_new_tty_pgrp(pty_fd, os_getpid());
printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno); if(err < 0){
exit(1); printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
}
if(tcsetpgrp(pty_fd, os_getpid()) < 0){
printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno);
exit(1); exit(1);
} }
if(read(pipe_fd, &c, sizeof(c)) != sizeof(c)) count = os_read_file(pipe_fd, &c, sizeof(c));
if(count != sizeof(c))
printk("winch_thread : failed to read synchronization byte, " printk("winch_thread : failed to read synchronization byte, "
"errno = %d\n", errno); "err = %d\n", -count);
while(1){ while(1){
pause(); pause();
if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){ count = os_write_file(pipe_fd, &c, sizeof(c));
printk("winch_thread : write failed, errno = %d\n", if(count != sizeof(c))
errno); printk("winch_thread : write failed, err = %d\n",
} -count);
} }
} }
...@@ -154,8 +154,8 @@ static int winch_tramp(int fd, void *device_data, int *fd_out) ...@@ -154,8 +154,8 @@ static int winch_tramp(int fd, void *device_data, int *fd_out)
char c; char c;
err = os_pipe(fds, 1, 1); err = os_pipe(fds, 1, 1);
if(err){ if(err < 0){
printk("winch_tramp : os_pipe failed, errno = %d\n", -err); printk("winch_tramp : os_pipe failed, err = %d\n", -err);
return(err); return(err);
} }
...@@ -168,12 +168,12 @@ static int winch_tramp(int fd, void *device_data, int *fd_out) ...@@ -168,12 +168,12 @@ static int winch_tramp(int fd, void *device_data, int *fd_out)
return(pid); return(pid);
} }
close(fds[1]); os_close_file(fds[1]);
*fd_out = fds[0]; *fd_out = fds[0];
n = read(fds[0], &c, sizeof(c)); n = os_read_file(fds[0], &c, sizeof(c));
if(n != sizeof(c)){ if(n != sizeof(c)){
printk("winch_tramp : failed to read synchronization byte\n"); printk("winch_tramp : failed to read synchronization byte\n");
printk("read returned %d, errno = %d\n", n, errno); printk("read failed, err = %d\n", -n);
printk("fd %d will not support SIGWINCH\n", fd); printk("fd %d will not support SIGWINCH\n", fd);
*fd_out = -1; *fd_out = -1;
} }
...@@ -183,20 +183,24 @@ static int winch_tramp(int fd, void *device_data, int *fd_out) ...@@ -183,20 +183,24 @@ static int winch_tramp(int fd, void *device_data, int *fd_out)
void register_winch(int fd, void *device_data) void register_winch(int fd, void *device_data)
{ {
int pid, thread, thread_fd; int pid, thread, thread_fd;
int count;
char c = 1; char c = 1;
if(!isatty(fd)) return; if(!isatty(fd))
return;
pid = tcgetpgrp(fd); pid = tcgetpgrp(fd);
if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
(pid == -1)){ device_data) && (pid == -1)){
thread = winch_tramp(fd, device_data, &thread_fd); thread = winch_tramp(fd, device_data, &thread_fd);
if(fd != -1){ if(fd != -1){
register_winch_irq(thread_fd, fd, thread, device_data); register_winch_irq(thread_fd, fd, thread, device_data);
if(write(thread_fd, &c, sizeof(c)) != sizeof(c)) count = os_write_file(thread_fd, &c, sizeof(c));
if(count != sizeof(c))
printk("register_winch : failed to write " printk("register_winch : failed to write "
"synchronization byte\n"); "synchronization byte, err = %d\n",
-count);
} }
} }
} }
......
#ifndef __COW_H__
#define __COW_H__
#include <asm/types.h>
#if __BYTE_ORDER == __BIG_ENDIAN
# define ntohll(x) (x)
# define htonll(x) (x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
# define ntohll(x) bswap_64(x)
# define htonll(x) bswap_64(x)
#else
#error "__BYTE_ORDER not defined"
#endif
extern int init_cow_file(int fd, char *cow_file, char *backing_file,
int sectorsize, int alignment, int *bitmap_offset_out,
unsigned long *bitmap_len_out, int *data_offset_out);
extern int file_reader(__u64 offset, char *buf, int len, void *arg);
extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
void *arg, __u32 *version_out,
char **backing_file_out, time_t *mtime_out,
__u64 *size_out, int *sectorsize_out,
__u32 *align_out, int *bitmap_offset_out);
extern int write_cow_header(char *cow_file, int fd, char *backing_file,
int sectorsize, int alignment, long long *size);
extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
int bitmap_offset, unsigned long *bitmap_len_out,
int *data_offset_out);
#endif
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
This diff is collapsed.
#ifndef __COW_SYS_H__
#define __COW_SYS_H__
#include "kern_util.h"
#include "user_util.h"
#include "os.h"
#include "user.h"
static inline void *cow_malloc(int size)
{
return(um_kmalloc(size));
}
static inline void cow_free(void *ptr)
{
kfree(ptr);
}
#define cow_printf printk
static inline char *cow_strdup(char *str)
{
return(uml_strdup(str));
}
static inline int cow_seek_file(int fd, __u64 offset)
{
return(os_seek_file(fd, offset));
}
static inline int cow_file_size(char *file, __u64 *size_out)
{
return(os_file_size(file, size_out));
}
static inline int cow_write_file(int fd, char *buf, int size)
{
return(os_write_file(fd, buf, size));
}
#endif
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/user.h>
#include <netinet/in.h>
#include "os.h"
#include "cow.h"
#include "cow_sys.h"
#define PATH_LEN_V1 256
struct cow_header_v1 {
int magic;
int version;
char backing_file[PATH_LEN_V1];
time_t mtime;
__u64 size;
int sectorsize;
};
#define PATH_LEN_V2 MAXPATHLEN
struct cow_header_v2 {
unsigned long magic;
unsigned long version;
char backing_file[PATH_LEN_V2];
time_t mtime;
__u64 size;
int sectorsize;
};
/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
* case other systems have different values for MAXPATHLEN
*/
#define PATH_LEN_V3 4096
/* Changes from V2 -
* PATH_LEN_V3 as described above
* Explicitly specify field bit lengths for systems with different
* lengths for the usual C types. Not sure whether char or
* time_t should be changed, this can be changed later without
* breaking compatibility
* Add alignment field so that different alignments can be used for the
* bitmap and data
* Add cow_format field to allow for the possibility of different ways
* of specifying the COW blocks. For now, the only value is 0,
* for the traditional COW bitmap.
* Move the backing_file field to the end of the header. This allows
* for the possibility of expanding it into the padding required
* by the bitmap alignment.
* The bitmap and data portions of the file will be aligned as specified
* by the alignment field. This is to allow COW files to be
* put on devices with restrictions on access alignments, such as
* /dev/raw, with a 512 byte alignment restriction. This also
* allows the data to be more aligned more strictly than on
* sector boundaries. This is needed for ubd-mmap, which needs
* the data to be page aligned.
* Fixed (finally!) the rounding bug
*/
struct cow_header_v3 {
__u32 magic;
__u32 version;
time_t mtime;
__u64 size;
__u32 sectorsize;
__u32 alignment;
__u32 cow_format;
char backing_file[PATH_LEN_V3];
};
/* COW format definitions - for now, we have only the usual COW bitmap */
#define COW_BITMAP 0
union cow_header {
struct cow_header_v1 v1;
struct cow_header_v2 v2;
struct cow_header_v3 v3;
};
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 3
#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
void cow_sizes(int version, __u64 size, int sectorsize, int align,
int bitmap_offset, unsigned long *bitmap_len_out,
int *data_offset_out)
{
if(version < 3){
*bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
*data_offset_out = bitmap_offset + *bitmap_len_out;
*data_offset_out = (*data_offset_out + sectorsize - 1) /
sectorsize;
*data_offset_out *= sectorsize;
}
else {
*bitmap_len_out = DIV_ROUND(size, sectorsize);
*bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
*data_offset_out = bitmap_offset + *bitmap_len_out;
*data_offset_out = ROUND_UP(*data_offset_out, align);
}
}
static int absolutize(char *to, int size, char *from)
{
char save_cwd[256], *slash;
int remaining;
if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
cow_printf("absolutize : unable to get cwd - errno = %d\n",
errno);
return(-1);
}
slash = strrchr(from, '/');
if(slash != NULL){
*slash = '\0';
if(chdir(from)){
*slash = '/';
cow_printf("absolutize : Can't cd to '%s' - "
"errno = %d\n", from, errno);
return(-1);
}
*slash = '/';
if(getcwd(to, size) == NULL){
cow_printf("absolutize : unable to get cwd of '%s' - "
"errno = %d\n", from, errno);
return(-1);
}
remaining = size - strlen(to);
if(strlen(slash) + 1 > remaining){
cow_printf("absolutize : unable to fit '%s' into %d "
"chars\n", from, size);
return(-1);
}
strcat(to, slash);
}
else {
if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
cow_printf("absolutize : unable to fit '%s' into %d "
"chars\n", from, size);
return(-1);
}
strcpy(to, save_cwd);
strcat(to, "/");
strcat(to, from);
}
chdir(save_cwd);
return(0);
}
int write_cow_header(char *cow_file, int fd, char *backing_file,
int sectorsize, int alignment, long long *size)
{
struct cow_header_v3 *header;
unsigned long modtime;
int err;
err = cow_seek_file(fd, 0);
if(err < 0){
cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
goto out;
}
err = -ENOMEM;
header = cow_malloc(sizeof(*header));
if(header == NULL){
cow_printf("Failed to allocate COW V3 header\n");
goto out;
}
header->magic = htonl(COW_MAGIC);
header->version = htonl(COW_VERSION);
err = -EINVAL;
if(strlen(backing_file) > sizeof(header->backing_file) - 1){
cow_printf("Backing file name \"%s\" is too long - names are "
"limited to %d characters\n", backing_file,
sizeof(header->backing_file) - 1);
goto out_free;
}
if(absolutize(header->backing_file, sizeof(header->backing_file),
backing_file))
goto out_free;
err = os_file_modtime(header->backing_file, &modtime);
if(err < 0){
cow_printf("Backing file '%s' mtime request failed, "
"err = %d\n", header->backing_file, -err);
goto out_free;
}
err = cow_file_size(header->backing_file, size);
if(err < 0){
cow_printf("Couldn't get size of backing file '%s', "
"err = %d\n", header->backing_file, -err);
goto out_free;
}
header->mtime = htonl(modtime);
header->size = htonll(*size);
header->sectorsize = htonl(sectorsize);
header->alignment = htonl(alignment);
header->cow_format = COW_BITMAP;
err = os_write_file(fd, header, sizeof(*header));
if(err != sizeof(*header)){
cow_printf("Write of header to new COW file '%s' failed, "
"err = %d\n", cow_file, -err);
goto out_free;
}
err = 0;
out_free:
cow_free(header);
out:
return(err);
}
int file_reader(__u64 offset, char *buf, int len, void *arg)
{
int fd = *((int *) arg);
return(pread(fd, buf, len, offset));
}
/* XXX Need to sanity-check the values read from the header */
int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
__u32 *version_out, char **backing_file_out,
time_t *mtime_out, __u64 *size_out,
int *sectorsize_out, __u32 *align_out,
int *bitmap_offset_out)
{
union cow_header *header;
char *file;
int err, n;
unsigned long version, magic;
header = cow_malloc(sizeof(*header));
if(header == NULL){
cow_printf("read_cow_header - Failed to allocate header\n");
return(-ENOMEM);
}
err = -EINVAL;
n = (*reader)(0, (char *) header, sizeof(*header), arg);
if(n < offsetof(typeof(header->v1), backing_file)){
cow_printf("read_cow_header - short header\n");
goto out;
}
magic = header->v1.magic;
if(magic == COW_MAGIC) {
version = header->v1.version;
}
else if(magic == ntohl(COW_MAGIC)){
version = ntohl(header->v1.version);
}
/* No error printed because the non-COW case comes through here */
else goto out;
*version_out = version;
if(version == 1){
if(n < sizeof(header->v1)){
cow_printf("read_cow_header - failed to read V1 "
"header\n");
goto out;
}
*mtime_out = header->v1.mtime;
*size_out = header->v1.size;
*sectorsize_out = header->v1.sectorsize;
*bitmap_offset_out = sizeof(header->v1);
*align_out = *sectorsize_out;
file = header->v1.backing_file;
}
else if(version == 2){
if(n < sizeof(header->v2)){
cow_printf("read_cow_header - failed to read V2 "
"header\n");
goto out;
}
*mtime_out = ntohl(header->v2.mtime);
*size_out = ntohll(header->v2.size);
*sectorsize_out = ntohl(header->v2.sectorsize);
*bitmap_offset_out = sizeof(header->v2);
*align_out = *sectorsize_out;
file = header->v2.backing_file;
}
else if(version == 3){
if(n < sizeof(header->v3)){
cow_printf("read_cow_header - failed to read V2 "
"header\n");
goto out;
}
*mtime_out = ntohl(header->v3.mtime);
*size_out = ntohll(header->v3.size);
*sectorsize_out = ntohl(header->v3.sectorsize);
*align_out = ntohl(header->v3.alignment);
*bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
file = header->v3.backing_file;
}
else {
cow_printf("read_cow_header - invalid COW version\n");
goto out;
}
err = -ENOMEM;
*backing_file_out = cow_strdup(file);
if(*backing_file_out == NULL){
cow_printf("read_cow_header - failed to allocate backing "
"file\n");
goto out;
}
err = 0;
out:
cow_free(header);
return(err);
}
int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
int alignment, int *bitmap_offset_out,
unsigned long *bitmap_len_out, int *data_offset_out)
{
__u64 size, offset;
char zero = 0;
int err;
err = write_cow_header(cow_file, fd, backing_file, sectorsize,
alignment, &size);
if(err)
goto out;
*bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
bitmap_len_out, data_offset_out);
offset = *data_offset_out + size - sizeof(zero);
err = cow_seek_file(fd, offset);
if(err < 0){
cow_printf("cow bitmap lseek failed : err = %d\n", -err);
goto out;
}
/* does not really matter how much we write it is just to set EOF
* this also sets the entire COW bitmap
* to zero without having to allocate it
*/
err = cow_write_file(fd, &zero, sizeof(zero));
if(err != sizeof(zero)){
cow_printf("Write of bitmap to new COW file '%s' failed, "
"err = %d\n", cow_file, -err);
err = -EINVAL;
goto out;
}
return(0);
out:
return(err);
}
/*
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -53,7 +53,8 @@ static int connect_to_switch(struct daemon_data *pri) ...@@ -53,7 +53,8 @@ static int connect_to_switch(struct daemon_data *pri)
struct request_v3 req; struct request_v3 req;
int fd, n, err; int fd, n, err;
if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
if(pri->control < 0){
printk("daemon_open : control socket failed, errno = %d\n", printk("daemon_open : control socket failed, errno = %d\n",
errno); errno);
return(-errno); return(-errno);
...@@ -67,7 +68,8 @@ static int connect_to_switch(struct daemon_data *pri) ...@@ -67,7 +68,8 @@ static int connect_to_switch(struct daemon_data *pri)
goto out; goto out;
} }
if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(fd < 0){
printk("daemon_open : data socket failed, errno = %d\n", printk("daemon_open : data socket failed, errno = %d\n",
errno); errno);
err = -errno; err = -errno;
...@@ -91,18 +93,18 @@ static int connect_to_switch(struct daemon_data *pri) ...@@ -91,18 +93,18 @@ static int connect_to_switch(struct daemon_data *pri)
req.version = SWITCH_VERSION; req.version = SWITCH_VERSION;
req.type = REQ_NEW_CONTROL; req.type = REQ_NEW_CONTROL;
req.sock = *local_addr; req.sock = *local_addr;
n = write(pri->control, &req, sizeof(req)); n = os_write_file(pri->control, &req, sizeof(req));
if(n != sizeof(req)){ if(n != sizeof(req)){
printk("daemon_open : control setup request returned %d, " printk("daemon_open : control setup request failed, err = %d\n",
"errno = %d\n", n, errno); -n);
err = -ENOTCONN; err = -ENOTCONN;
goto out; goto out;
} }
n = read(pri->control, sun, sizeof(*sun)); n = os_read_file(pri->control, sun, sizeof(*sun));
if(n != sizeof(*sun)){ if(n != sizeof(*sun)){
printk("daemon_open : read of data socket returned %d, " printk("daemon_open : read of data socket failed, err = %d\n",
"errno = %d\n", n, errno); -n);
err = -ENOTCONN; err = -ENOTCONN;
goto out_close; goto out_close;
} }
...@@ -111,9 +113,9 @@ static int connect_to_switch(struct daemon_data *pri) ...@@ -111,9 +113,9 @@ static int connect_to_switch(struct daemon_data *pri)
return(fd); return(fd);
out_close: out_close:
close(fd); os_close_file(fd);
out: out:
close(pri->control); os_close_file(pri->control);
return(err); return(err);
} }
...@@ -153,8 +155,8 @@ static void daemon_remove(void *data) ...@@ -153,8 +155,8 @@ static void daemon_remove(void *data)
{ {
struct daemon_data *pri = data; struct daemon_data *pri = data;
close(pri->fd); os_close_file(pri->fd);
close(pri->control); os_close_file(pri->control);
if(pri->data_addr != NULL) kfree(pri->data_addr); if(pri->data_addr != NULL) kfree(pri->data_addr);
if(pri->ctl_addr != NULL) kfree(pri->ctl_addr); if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
if(pri->local_addr != NULL) kfree(pri->local_addr); if(pri->local_addr != NULL) kfree(pri->local_addr);
......
...@@ -35,7 +35,8 @@ void *fd_init(char *str, int device, struct chan_opts *opts) ...@@ -35,7 +35,8 @@ void *fd_init(char *str, int device, struct chan_opts *opts)
printk("fd_init : couldn't parse file descriptor '%s'\n", str); printk("fd_init : couldn't parse file descriptor '%s'\n", str);
return(NULL); return(NULL);
} }
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); data = um_kmalloc(sizeof(*data));
if(data == NULL) return(NULL);
*data = ((struct fd_chan) { .fd = n, *data = ((struct fd_chan) { .fd = n,
.raw = opts->raw }); .raw = opts->raw });
return(data); return(data);
......
...@@ -27,10 +27,10 @@ static void pre_exec(void *d) ...@@ -27,10 +27,10 @@ static void pre_exec(void *d)
dup2(data->stdin, 0); dup2(data->stdin, 0);
dup2(data->stdout, 1); dup2(data->stdout, 1);
dup2(data->stdout, 2); dup2(data->stdout, 2);
close(data->stdin); os_close_file(data->stdin);
close(data->stdout); os_close_file(data->stdout);
close(data->close_me[0]); os_close_file(data->close_me[0]);
close(data->close_me[1]); os_close_file(data->close_me[1]);
} }
int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
...@@ -44,15 +44,15 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) ...@@ -44,15 +44,15 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
char **args = NULL; char **args = NULL;
err = os_pipe(in_fds, 1, 0); err = os_pipe(in_fds, 1, 0);
if(err){ if(err < 0){
printk("harddog_open - os_pipe failed, errno = %d\n", -err); printk("harddog_open - os_pipe failed, err = %d\n", -err);
return(err); goto out;
} }
err = os_pipe(out_fds, 1, 0); err = os_pipe(out_fds, 1, 0);
if(err){ if(err < 0){
printk("harddog_open - os_pipe failed, errno = %d\n", -err); printk("harddog_open - os_pipe failed, err = %d\n", -err);
return(err); goto out_close_in;
} }
data.stdin = out_fds[0]; data.stdin = out_fds[0];
...@@ -72,42 +72,47 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) ...@@ -72,42 +72,47 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
pid = run_helper(pre_exec, &data, args, NULL); pid = run_helper(pre_exec, &data, args, NULL);
close(out_fds[0]); os_close_file(out_fds[0]);
close(in_fds[1]); os_close_file(in_fds[1]);
if(pid < 0){ if(pid < 0){
err = -pid; err = -pid;
printk("harddog_open - run_helper failed, errno = %d\n", err); printk("harddog_open - run_helper failed, errno = %d\n", -err);
goto out; goto out_close_out;
} }
n = read(in_fds[0], &c, sizeof(c)); n = os_read_file(in_fds[0], &c, sizeof(c));
if(n == 0){ if(n == 0){
printk("harddog_open - EOF on watchdog pipe\n"); printk("harddog_open - EOF on watchdog pipe\n");
helper_wait(pid); helper_wait(pid);
err = -EIO; err = -EIO;
goto out; goto out_close_out;
} }
else if(n < 0){ else if(n < 0){
printk("harddog_open - read of watchdog pipe failed, " printk("harddog_open - read of watchdog pipe failed, "
"errno = %d\n", errno); "err = %d\n", -n);
helper_wait(pid); helper_wait(pid);
err = -errno; err = n;
goto out; goto out_close_out;
} }
*in_fd_ret = in_fds[0]; *in_fd_ret = in_fds[0];
*out_fd_ret = out_fds[1]; *out_fd_ret = out_fds[1];
return(0); return(0);
out_close_in:
os_close_file(in_fds[0]);
os_close_file(in_fds[1]);
out_close_out:
os_close_file(out_fds[0]);
os_close_file(out_fds[1]);
out: out:
close(out_fds[1]);
close(in_fds[0]);
return(err); return(err);
} }
void stop_watchdog(int in_fd, int out_fd) void stop_watchdog(int in_fd, int out_fd)
{ {
close(in_fd); os_close_file(in_fd);
close(out_fd); os_close_file(out_fd);
} }
int ping_watchdog(int fd) int ping_watchdog(int fd)
...@@ -115,11 +120,12 @@ int ping_watchdog(int fd) ...@@ -115,11 +120,12 @@ int ping_watchdog(int fd)
int n; int n;
char c = '\n'; char c = '\n';
n = write(fd, &c, sizeof(c)); n = os_write_file(fd, &c, sizeof(c));
if(n < sizeof(c)){ if(n != sizeof(c)){
printk("ping_watchdog - write failed, errno = %d\n", printk("ping_watchdog - write failed, err = %d\n", -n);
errno); if(n < 0)
return(-errno); return(n);
return(-EIO);
} }
return 1; return 1;
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
#include "linux/config.h" #include "linux/config.h"
#include "linux/module.h" #include "linux/module.h"
#include "linux/version.h"
#include "linux/init.h" #include "linux/init.h"
#include "linux/slab.h" #include "linux/slab.h"
#include "linux/fs.h" #include "linux/fs.h"
#include "linux/sound.h" #include "linux/sound.h"
#include "linux/soundcard.h" #include "linux/soundcard.h"
#include "asm/uaccess.h"
#include "kern_util.h" #include "kern_util.h"
#include "init.h" #include "init.h"
#include "hostaudio.h" #include "hostaudio.h"
...@@ -19,30 +19,39 @@ ...@@ -19,30 +19,39 @@
char *dsp = HOSTAUDIO_DEV_DSP; char *dsp = HOSTAUDIO_DEV_DSP;
char *mixer = HOSTAUDIO_DEV_MIXER; char *mixer = HOSTAUDIO_DEV_MIXER;
#define DSP_HELP \
" This is used to specify the host dsp device to the hostaudio driver.\n" \
" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
#define MIXER_HELP \
" This is used to specify the host mixer device to the hostaudio driver.\n" \
" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
#ifndef MODULE #ifndef MODULE
static int set_dsp(char *name, int *add) static int set_dsp(char *name, int *add)
{ {
dsp = uml_strdup(name); dsp = name;
return(0); return(0);
} }
__uml_setup("dsp=", set_dsp, __uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
"dsp=<dsp device>\n"
" This is used to specify the host dsp device to the hostaudio driver.\n"
" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
);
static int set_mixer(char *name, int *add) static int set_mixer(char *name, int *add)
{ {
mixer = uml_strdup(name); mixer = name;
return(0); return(0);
} }
__uml_setup("mixer=", set_mixer, __uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
"mixer=<mixer device>\n"
" This is used to specify the host mixer device to the hostaudio driver.\n" #else /*MODULE*/
" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
); MODULE_PARM(dsp, "s");
MODULE_PARM_DESC(dsp, DSP_HELP);
MODULE_PARM(mixer, "s");
MODULE_PARM_DESC(mixer, MIXER_HELP);
#endif #endif
/* /dev/dsp file operations */ /* /dev/dsp file operations */
...@@ -51,23 +60,55 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, ...@@ -51,23 +60,55 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
struct hostaudio_state *state = file->private_data; struct hostaudio_state *state = file->private_data;
void *kbuf;
int err;
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: read called, count = %d\n", count); printk("hostaudio: read called, count = %d\n", count);
#endif #endif
return(hostaudio_read_user(state, buffer, count, ppos)); kbuf = kmalloc(count, GFP_KERNEL);
if(kbuf == NULL)
return(-ENOMEM);
err = hostaudio_read_user(state, kbuf, count, ppos);
if(err < 0)
goto out;
if(copy_to_user(buffer, kbuf, err))
err = -EFAULT;
out:
kfree(kbuf);
return(err);
} }
static ssize_t hostaudio_write(struct file *file, const char *buffer, static ssize_t hostaudio_write(struct file *file, const char *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct hostaudio_state *state = file->private_data; struct hostaudio_state *state = file->private_data;
void *kbuf;
int err;
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: write called, count = %d\n", count); printk("hostaudio: write called, count = %d\n", count);
#endif #endif
return(hostaudio_write_user(state, buffer, count, ppos));
kbuf = kmalloc(count, GFP_KERNEL);
if(kbuf == NULL)
return(-ENOMEM);
err = -EFAULT;
if(copy_from_user(kbuf, buffer, count))
goto out;
err = hostaudio_write_user(state, kbuf, count, ppos);
if(err < 0)
goto out;
out:
kfree(kbuf);
return(err);
} }
static unsigned int hostaudio_poll(struct file *file, static unsigned int hostaudio_poll(struct file *file,
...@@ -86,12 +127,43 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, ...@@ -86,12 +127,43 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct hostaudio_state *state = file->private_data; struct hostaudio_state *state = file->private_data;
unsigned long data = 0;
int err;
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: ioctl called, cmd = %u\n", cmd); printk("hostaudio: ioctl called, cmd = %u\n", cmd);
#endif #endif
switch(cmd){
return(hostaudio_ioctl_user(state, cmd, arg)); case SNDCTL_DSP_SPEED:
case SNDCTL_DSP_STEREO:
case SNDCTL_DSP_GETBLKSIZE:
case SNDCTL_DSP_CHANNELS:
case SNDCTL_DSP_SUBDIVIDE:
case SNDCTL_DSP_SETFRAGMENT:
if(get_user(data, (int *) arg))
return(-EFAULT);
break;
default:
break;
}
err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data);
switch(cmd){
case SNDCTL_DSP_SPEED:
case SNDCTL_DSP_STEREO:
case SNDCTL_DSP_GETBLKSIZE:
case SNDCTL_DSP_CHANNELS:
case SNDCTL_DSP_SUBDIVIDE:
case SNDCTL_DSP_SETFRAGMENT:
if(put_user(data, (int *) arg))
return(-EFAULT);
break;
default:
break;
}
return(err);
} }
static int hostaudio_open(struct inode *inode, struct file *file) static int hostaudio_open(struct inode *inode, struct file *file)
...@@ -225,7 +297,8 @@ MODULE_LICENSE("GPL"); ...@@ -225,7 +297,8 @@ MODULE_LICENSE("GPL");
static int __init hostaudio_init_module(void) static int __init hostaudio_init_module(void)
{ {
printk(KERN_INFO "UML Audio Relay\n"); printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
dsp, mixer);
module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
if(module_data.dev_audio < 0){ if(module_data.dev_audio < 0){
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include "hostaudio.h" #include "hostaudio.h"
...@@ -20,45 +17,31 @@ ...@@ -20,45 +17,31 @@
ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
ssize_t ret;
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: read_user called, count = %d\n", count); printk("hostaudio: read_user called, count = %d\n", count);
#endif #endif
ret = read(state->fd, buffer, count); return(os_read_file(state->fd, buffer, count));
if(ret < 0) return(-errno);
return(ret);
} }
ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer, ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
ssize_t ret;
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: write_user called, count = %d\n", count); printk("hostaudio: write_user called, count = %d\n", count);
#endif #endif
ret = write(state->fd, buffer, count); return(os_write_file(state->fd, buffer, count));
if(ret < 0) return(-errno);
return(ret);
} }
int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int ret;
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: ioctl_user called, cmd = %u\n", cmd); printk("hostaudio: ioctl_user called, cmd = %u\n", cmd);
#endif #endif
ret = ioctl(state->fd, cmd, arg); return(os_ioctl_generic(state->fd, cmd, arg));
if(ret < 0) return(-errno);
return(ret);
} }
int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
...@@ -67,14 +50,15 @@ int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) ...@@ -67,14 +50,15 @@ int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
printk("hostaudio: open_user called\n"); printk("hostaudio: open_user called\n");
#endif #endif
state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
if(state->fd >= 0) return(0);
printk("hostaudio_open_user failed to open '%s', errno = %d\n", if(state->fd < 0) {
dsp, errno); printk("hostaudio_open_user failed to open '%s', err = %d\n",
dsp, -state->fd);
return(state->fd);
}
return(-errno); return(0);
} }
int hostaudio_release_user(struct hostaudio_state *state) int hostaudio_release_user(struct hostaudio_state *state)
...@@ -82,10 +66,10 @@ int hostaudio_release_user(struct hostaudio_state *state) ...@@ -82,10 +66,10 @@ int hostaudio_release_user(struct hostaudio_state *state)
#ifdef DEBUG #ifdef DEBUG
printk("hostaudio: release called\n"); printk("hostaudio: release called\n");
#endif #endif
if(state->fd >= 0){ if(state->fd >= 0){
close(state->fd); os_close_file(state->fd);
state->fd=-1; state->fd = -1;
} }
return(0); return(0);
} }
...@@ -95,15 +79,11 @@ int hostaudio_release_user(struct hostaudio_state *state) ...@@ -95,15 +79,11 @@ int hostaudio_release_user(struct hostaudio_state *state)
int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int ret;
#ifdef DEBUG #ifdef DEBUG
printk("hostmixer: ioctl_user called cmd = %u\n",cmd); printk("hostmixer: ioctl_user called cmd = %u\n",cmd);
#endif #endif
ret = ioctl(state->fd, cmd, arg); return(os_ioctl_generic(state->fd, cmd, arg));
if(ret < 0)
return(-errno);
return(ret);
} }
int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
...@@ -115,12 +95,13 @@ int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, ...@@ -115,12 +95,13 @@ int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
if(state->fd >= 0) return(0); if(state->fd < 0) {
printk("hostaudio_open_mixdev_user failed to open '%s', "
printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n", "err = %d\n", mixer, state->fd);
mixer, errno); return(state->fd);
}
return(-errno); return(0);
} }
int hostmixer_release_mixdev_user(struct hostmixer_state *state) int hostmixer_release_mixdev_user(struct hostmixer_state *state)
...@@ -130,7 +111,7 @@ int hostmixer_release_mixdev_user(struct hostmixer_state *state) ...@@ -130,7 +111,7 @@ int hostmixer_release_mixdev_user(struct hostmixer_state *state)
#endif #endif
if(state->fd >= 0){ if(state->fd >= 0){
close(state->fd); os_close_file(state->fd);
state->fd = -1; state->fd = -1;
} }
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#include "linux/sched.h" #include "linux/sched.h"
#include "linux/slab.h" #include "linux/slab.h"
#include "linux/list.h" #include "linux/list.h"
#include "linux/interrupt.h"
#include "linux/devfs_fs_kernel.h" #include "linux/devfs_fs_kernel.h"
#include "asm/irq.h"
#include "asm/uaccess.h" #include "asm/uaccess.h"
#include "chan_kern.h" #include "chan_kern.h"
#include "irq_user.h" #include "irq_user.h"
...@@ -16,38 +16,55 @@ ...@@ -16,38 +16,55 @@
#include "user_util.h" #include "user_util.h"
#include "kern_util.h" #include "kern_util.h"
#include "os.h" #include "os.h"
#include "irq_kern.h"
#define LINE_BUFSIZE 4096 #define LINE_BUFSIZE 4096
void line_interrupt(int irq, void *data, struct pt_regs *unused) static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
{ {
struct line *dev = data; struct line *dev = data;
if(dev->count > 0) if(dev->count > 0)
chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq,
dev); dev);
return IRQ_HANDLED;
} }
void line_timer_cb(void *arg) static void line_timer_cb(void *arg)
{ {
struct line *dev = arg; struct line *dev = arg;
line_interrupt(dev->driver->read_irq, dev, NULL); line_interrupt(dev->driver->read_irq, dev, NULL);
} }
static void buffer_data(struct line *line, const char *buf, int len) static int write_room(struct line *dev)
{ {
int end; int n;
if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
n = dev->head - dev->tail;
if(n <= 0) n = LINE_BUFSIZE + n;
return(n - 1);
}
static int buffer_data(struct line *line, const char *buf, int len)
{
int end, room;
if(line->buffer == NULL){ if(line->buffer == NULL){
line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
if(line->buffer == NULL){ if(line->buffer == NULL){
printk("buffer_data - atomic allocation failed\n"); printk("buffer_data - atomic allocation failed\n");
return; return(0);
} }
line->head = line->buffer; line->head = line->buffer;
line->tail = line->buffer; line->tail = line->buffer;
} }
room = write_room(line);
len = (len > room) ? room : len;
end = line->buffer + LINE_BUFSIZE - line->tail; end = line->buffer + LINE_BUFSIZE - line->tail;
if(len < end){ if(len < end){
memcpy(line->tail, buf, len); memcpy(line->tail, buf, len);
...@@ -60,6 +77,8 @@ static void buffer_data(struct line *line, const char *buf, int len) ...@@ -60,6 +77,8 @@ static void buffer_data(struct line *line, const char *buf, int len)
memcpy(line->buffer, buf, len); memcpy(line->buffer, buf, len);
line->tail = line->buffer + len; line->tail = line->buffer + len;
} }
return(len);
} }
static int flush_buffer(struct line *line) static int flush_buffer(struct line *line)
...@@ -95,7 +114,7 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, ...@@ -95,7 +114,7 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user,
struct line *line; struct line *line;
char *new; char *new;
unsigned long flags; unsigned long flags;
int n, err, i; int n, err, i, ret = 0;
if(tty->stopped) return 0; if(tty->stopped) return 0;
...@@ -104,9 +123,13 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, ...@@ -104,9 +123,13 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user,
if(new == NULL) if(new == NULL)
return(0); return(0);
n = copy_from_user(new, buf, len); n = copy_from_user(new, buf, len);
if(n == len)
return(-EFAULT);
buf = new; buf = new;
if(n == len){
len = -EFAULT;
goto out_free;
}
len -= n;
} }
i = tty->index; i = tty->index;
...@@ -115,41 +138,50 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, ...@@ -115,41 +138,50 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user,
down(&line->sem); down(&line->sem);
if(line->head != line->tail){ if(line->head != line->tail){
local_irq_save(flags); local_irq_save(flags);
buffer_data(line, buf, len); ret += buffer_data(line, buf, len);
err = flush_buffer(line); err = flush_buffer(line);
local_irq_restore(flags); local_irq_restore(flags);
if(err <= 0) if(err <= 0)
goto out; goto out_up;
} }
else { else {
n = write_chan(&line->chan_list, buf, len, n = write_chan(&line->chan_list, buf, len,
line->driver->write_irq); line->driver->write_irq);
if(n < 0){ if(n < 0){
len = n; ret = n;
goto out; goto out_up;
} }
if(n < len)
buffer_data(line, buf + n, len - n); len -= n;
ret += n;
if(len > 0)
ret += buffer_data(line, buf + n, len);
} }
out: out_up:
up(&line->sem); up(&line->sem);
return(len); out_free:
if(from_user)
kfree(buf);
return(ret);
} }
void line_write_interrupt(int irq, void *data, struct pt_regs *unused) static irqreturn_t line_write_interrupt(int irq, void *data,
struct pt_regs *unused)
{ {
struct line *dev = data; struct line *dev = data;
struct tty_struct *tty = dev->tty; struct tty_struct *tty = dev->tty;
int err; int err;
err = flush_buffer(dev); err = flush_buffer(dev);
if(err == 0) return; if(err == 0)
return(IRQ_NONE);
else if(err < 0){ else if(err < 0){
dev->head = dev->buffer; dev->head = dev->buffer;
dev->tail = dev->buffer; dev->tail = dev->buffer;
} }
if(tty == NULL) return; if(tty == NULL)
return(IRQ_NONE);
if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
(tty->ldisc.write_wakeup != NULL)) (tty->ldisc.write_wakeup != NULL))
...@@ -161,21 +193,9 @@ void line_write_interrupt(int irq, void *data, struct pt_regs *unused) ...@@ -161,21 +193,9 @@ void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
* writes. * writes.
*/ */
if (waitqueue_active(&tty->write_wait)) if(waitqueue_active(&tty->write_wait))
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
return(IRQ_HANDLED);
}
int line_write_room(struct tty_struct *tty)
{
struct line *dev = tty->driver_data;
int n;
if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
n = dev->head - dev->tail;
if(n <= 0) n = LINE_BUFSIZE + n;
return(n - 1);
} }
int line_setup_irq(int fd, int input, int output, void *data) int line_setup_irq(int fd, int input, int output, void *data)
...@@ -305,7 +325,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) ...@@ -305,7 +325,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
if(*end != '='){ if(*end != '='){
printk(KERN_ERR "line_setup failed to parse \"%s\"\n", printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init); init);
return(1); return(0);
} }
init = end; init = end;
} }
...@@ -313,12 +333,12 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) ...@@ -313,12 +333,12 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
if((n >= 0) && (n >= num)){ if((n >= 0) && (n >= num)){
printk("line_setup - %d out of range ((0 ... %d) allowed)\n", printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
n, num); n, num);
return(1); return(0);
} }
else if(n >= 0){ else if(n >= 0){
if(lines[n].count > 0){ if(lines[n].count > 0){
printk("line_setup - device %d is open\n", n); printk("line_setup - device %d is open\n", n);
return(1); return(0);
} }
if(lines[n].init_pri <= INIT_ONE){ if(lines[n].init_pri <= INIT_ONE){
lines[n].init_pri = INIT_ONE; lines[n].init_pri = INIT_ONE;
...@@ -332,7 +352,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) ...@@ -332,7 +352,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
else if(!all_allowed){ else if(!all_allowed){
printk("line_setup - can't configure all devices from " printk("line_setup - can't configure all devices from "
"mconsole\n"); "mconsole\n");
return(1); return(0);
} }
else { else {
for(i = 0; i < num; i++){ for(i = 0; i < num; i++){
...@@ -346,7 +366,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) ...@@ -346,7 +366,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
} }
} }
} }
return(0); return(1);
} }
int line_config(struct line *lines, int num, char *str) int line_config(struct line *lines, int num, char *str)
...@@ -357,7 +377,7 @@ int line_config(struct line *lines, int num, char *str) ...@@ -357,7 +377,7 @@ int line_config(struct line *lines, int num, char *str)
printk("line_config - uml_strdup failed\n"); printk("line_config - uml_strdup failed\n");
return(-ENOMEM); return(-ENOMEM);
} }
return(line_setup(lines, num, new, 0)); return(!line_setup(lines, num, new, 0));
} }
int line_get_config(char *name, struct line *lines, int num, char *str, int line_get_config(char *name, struct line *lines, int num, char *str,
...@@ -369,7 +389,7 @@ int line_get_config(char *name, struct line *lines, int num, char *str, ...@@ -369,7 +389,7 @@ int line_get_config(char *name, struct line *lines, int num, char *str,
dev = simple_strtoul(name, &end, 0); dev = simple_strtoul(name, &end, 0);
if((*end != '\0') || (end == name)){ if((*end != '\0') || (end == name)){
*error_out = "line_setup failed to parse device number"; *error_out = "line_get_config failed to parse device number";
return(0); return(0);
} }
...@@ -379,15 +399,15 @@ int line_get_config(char *name, struct line *lines, int num, char *str, ...@@ -379,15 +399,15 @@ int line_get_config(char *name, struct line *lines, int num, char *str,
} }
line = &lines[dev]; line = &lines[dev];
down(&line->sem); down(&line->sem);
if(!line->valid) if(!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1); CONFIG_CHUNK(str, size, n, "none", 1);
else if(line->count == 0) else if(line->count == 0)
CONFIG_CHUNK(str, size, n, line->init_str, 1); CONFIG_CHUNK(str, size, n, line->init_str, 1);
else n = chan_config_string(&line->chan_list, str, size, error_out); else n = chan_config_string(&line->chan_list, str, size, error_out);
up(&line->sem); up(&line->sem);
return(n); return(n);
} }
...@@ -396,7 +416,14 @@ int line_remove(struct line *lines, int num, char *str) ...@@ -396,7 +416,14 @@ int line_remove(struct line *lines, int num, char *str)
char config[sizeof("conxxxx=none\0")]; char config[sizeof("conxxxx=none\0")];
sprintf(config, "%s=none", str); sprintf(config, "%s=none", str);
return(line_setup(lines, num, config, 0)); return(!line_setup(lines, num, config, 0));
}
int line_write_room(struct tty_struct *tty)
{
struct line *dev = tty->driver_data;
return(write_room(dev));
} }
struct tty_driver *line_register_devfs(struct lines *set, struct tty_driver *line_register_devfs(struct lines *set,
...@@ -412,7 +439,8 @@ struct tty_driver *line_register_devfs(struct lines *set, ...@@ -412,7 +439,8 @@ struct tty_driver *line_register_devfs(struct lines *set,
return NULL; return NULL;
driver->driver_name = line_driver->name; driver->driver_name = line_driver->name;
driver->name = line_driver->devfs_name; driver->name = line_driver->device_name;
driver->devfs_name = line_driver->devfs_name;
driver->major = line_driver->major; driver->major = line_driver->major;
driver->minor_start = line_driver->minor_start; driver->minor_start = line_driver->minor_start;
driver->type = line_driver->type; driver->type = line_driver->type;
...@@ -432,7 +460,7 @@ struct tty_driver *line_register_devfs(struct lines *set, ...@@ -432,7 +460,7 @@ struct tty_driver *line_register_devfs(struct lines *set,
for(i = 0; i < nlines; i++){ for(i = 0; i < nlines; i++){
if(!lines[i].valid) if(!lines[i].valid)
tty_unregister_devfs(driver, i); tty_unregister_device(driver, i);
} }
mconsole_register_dev(&line_driver->mc); mconsole_register_dev(&line_driver->mc);
...@@ -465,24 +493,25 @@ struct winch { ...@@ -465,24 +493,25 @@ struct winch {
struct line *line; struct line *line;
}; };
void winch_interrupt(int irq, void *data, struct pt_regs *unused) irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
{ {
struct winch *winch = data; struct winch *winch = data;
struct tty_struct *tty; struct tty_struct *tty;
int err; int err;
char c; char c;
err = generic_read(winch->fd, &c, NULL); if(winch->fd != -1){
if(err < 0){ err = generic_read(winch->fd, &c, NULL);
if(err != -EAGAIN){ if(err < 0){
printk("winch_interrupt : read failed, errno = %d\n", if(err != -EAGAIN){
-err); printk("winch_interrupt : read failed, "
printk("fd %d is losing SIGWINCH support\n", "errno = %d\n", -err);
winch->tty_fd); printk("fd %d is losing SIGWINCH support\n",
free_irq(irq, data); winch->tty_fd);
return; return(IRQ_HANDLED);
}
goto out;
} }
goto out;
} }
tty = winch->line->tty; tty = winch->line->tty;
if(tty != NULL){ if(tty != NULL){
...@@ -492,7 +521,9 @@ void winch_interrupt(int irq, void *data, struct pt_regs *unused) ...@@ -492,7 +521,9 @@ void winch_interrupt(int irq, void *data, struct pt_regs *unused)
kill_pg(tty->pgrp, SIGWINCH, 1); kill_pg(tty->pgrp, SIGWINCH, 1);
} }
out: out:
reactivate_fd(winch->fd, WINCH_IRQ); if(winch->fd != -1)
reactivate_fd(winch->fd, WINCH_IRQ);
return(IRQ_HANDLED);
} }
DECLARE_MUTEX(winch_handler_sem); DECLARE_MUTEX(winch_handler_sem);
...@@ -529,7 +560,10 @@ static void winch_cleanup(void) ...@@ -529,7 +560,10 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){ list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list); winch = list_entry(ele, struct winch, list);
close(winch->fd); if(winch->fd != -1){
deactivate_fd(winch->fd, WINCH_IRQ);
os_close_file(winch->fd);
}
if(winch->pid != -1) if(winch->pid != -1)
os_kill_process(winch->pid, 1); os_kill_process(winch->pid, 1);
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "kern_util.h" #include "kern_util.h"
#include "user_util.h" #include "user_util.h"
#include "user.h" #include "user.h"
#include "os.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
...@@ -62,7 +63,8 @@ static int mcast_open(void *data) ...@@ -62,7 +63,8 @@ static int mcast_open(void *data)
goto out; goto out;
} }
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0){
printk("mcast_open : data socket failed, errno = %d\n", printk("mcast_open : data socket failed, errno = %d\n",
errno); errno);
fd = -ENOMEM; fd = -ENOMEM;
...@@ -72,7 +74,7 @@ static int mcast_open(void *data) ...@@ -72,7 +74,7 @@ static int mcast_open(void *data)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
errno); errno);
close(fd); os_close_file(fd);
fd = -EINVAL; fd = -EINVAL;
goto out; goto out;
} }
...@@ -82,7 +84,7 @@ static int mcast_open(void *data) ...@@ -82,7 +84,7 @@ static int mcast_open(void *data)
sizeof(pri->ttl)) < 0) { sizeof(pri->ttl)) < 0) {
printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
errno); errno);
close(fd); os_close_file(fd);
fd = -EINVAL; fd = -EINVAL;
goto out; goto out;
} }
...@@ -91,7 +93,7 @@ static int mcast_open(void *data) ...@@ -91,7 +93,7 @@ static int mcast_open(void *data)
if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
errno); errno);
close(fd); os_close_file(fd);
fd = -EINVAL; fd = -EINVAL;
goto out; goto out;
} }
...@@ -99,7 +101,7 @@ static int mcast_open(void *data) ...@@ -99,7 +101,7 @@ static int mcast_open(void *data)
/* bind socket to mcast address */ /* bind socket to mcast address */
if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
printk("mcast_open : data bind failed, errno = %d\n", errno); printk("mcast_open : data bind failed, errno = %d\n", errno);
close(fd); os_close_file(fd);
fd = -EINVAL; fd = -EINVAL;
goto out; goto out;
} }
...@@ -115,7 +117,7 @@ static int mcast_open(void *data) ...@@ -115,7 +117,7 @@ static int mcast_open(void *data)
"interface on the host.\n"); "interface on the host.\n");
printk("eth0 should be configured in order to use the " printk("eth0 should be configured in order to use the "
"multicast transport.\n"); "multicast transport.\n");
close(fd); os_close_file(fd);
fd = -EINVAL; fd = -EINVAL;
} }
...@@ -137,7 +139,7 @@ static void mcast_close(int fd, void *data) ...@@ -137,7 +139,7 @@ static void mcast_close(int fd, void *data)
errno); errno);
} }
close(fd); os_close_file(fd);
} }
int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
......
/* /*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include "linux/sysrq.h" #include "linux/sysrq.h"
#include "linux/workqueue.h" #include "linux/workqueue.h"
#include "linux/module.h" #include "linux/module.h"
#include "linux/file.h"
#include "linux/fs.h"
#include "linux/namei.h"
#include "linux/proc_fs.h" #include "linux/proc_fs.h"
#include "asm/irq.h" #include "asm/irq.h"
#include "asm/uaccess.h" #include "asm/uaccess.h"
...@@ -27,6 +30,7 @@ ...@@ -27,6 +30,7 @@
#include "init.h" #include "init.h"
#include "os.h" #include "os.h"
#include "umid.h" #include "umid.h"
#include "irq_kern.h"
static int do_unlink_socket(struct notifier_block *notifier, static int do_unlink_socket(struct notifier_block *notifier,
unsigned long what, void *data) unsigned long what, void *data)
...@@ -67,7 +71,7 @@ void mc_work_proc(void *unused) ...@@ -67,7 +71,7 @@ void mc_work_proc(void *unused)
DECLARE_WORK(mconsole_work, mc_work_proc, NULL); DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
int fd; int fd;
struct mconsole_entry *new; struct mconsole_entry *new;
...@@ -75,9 +79,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -75,9 +79,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
fd = (int) dev_id; fd = (int) dev_id;
while (mconsole_get_request(fd, &req)){ while (mconsole_get_request(fd, &req)){
if(req.cmd->as_interrupt) (*req.cmd->handler)(&req); if(req.cmd->context == MCONSOLE_INTR)
(*req.cmd->handler)(&req);
else { else {
new = kmalloc(sizeof(req), GFP_ATOMIC); new = kmalloc(sizeof(*new), GFP_ATOMIC);
if(new == NULL) if(new == NULL)
mconsole_reply(&req, "Out of memory", 1, 0); mconsole_reply(&req, "Out of memory", 1, 0);
else { else {
...@@ -88,6 +93,7 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -88,6 +93,7 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} }
if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
reactivate_fd(fd, MCONSOLE_IRQ); reactivate_fd(fd, MCONSOLE_IRQ);
return(IRQ_HANDLED);
} }
void mconsole_version(struct mc_request *req) void mconsole_version(struct mc_request *req)
...@@ -100,20 +106,109 @@ void mconsole_version(struct mc_request *req) ...@@ -100,20 +106,109 @@ void mconsole_version(struct mc_request *req)
mconsole_reply(req, version, 0, 0); mconsole_reply(req, version, 0, 0);
} }
void mconsole_log(struct mc_request *req)
{
int len;
char *ptr = req->request.data;
ptr += strlen("log ");
len = req->len - (ptr - req->request.data);
printk("%.*s", len, ptr);
mconsole_reply(req, "", 0, 0);
}
void mconsole_proc(struct mc_request *req)
{
struct nameidata nd;
struct file_system_type *proc;
struct super_block *super;
struct file *file;
int n, err;
char *ptr = req->request.data, *buf;
ptr += strlen("proc");
while(isspace(*ptr)) ptr++;
proc = get_fs_type("proc");
if(proc == NULL){
mconsole_reply(req, "procfs not registered", 1, 0);
goto out;
}
super = (*proc->get_sb)(proc, 0, NULL, NULL);
put_filesystem(proc);
if(super == NULL){
mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
goto out;
}
up_write(&super->s_umount);
nd.dentry = super->s_root;
nd.mnt = NULL;
nd.flags = O_RDONLY + 1;
nd.last_type = LAST_ROOT;
err = link_path_walk(ptr, &nd);
if(err){
mconsole_reply(req, "Failed to look up file", 1, 0);
goto out_kill;
}
file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
if(IS_ERR(file)){
mconsole_reply(req, "Failed to open file", 1, 0);
goto out_kill;
}
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if(buf == NULL){
mconsole_reply(req, "Failed to allocate buffer", 1, 0);
goto out_fput;
}
if((file->f_op != NULL) && (file->f_op->read != NULL)){
do {
n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
&file->f_pos);
if(n >= 0){
buf[n] = '\0';
mconsole_reply(req, buf, 0, (n > 0));
}
else {
mconsole_reply(req, "Read of file failed",
1, 0);
goto out_free;
}
} while(n > 0);
}
else mconsole_reply(req, "", 0, 0);
out_free:
kfree(buf);
out_fput:
fput(file);
out_kill:
deactivate_super(super);
out: ;
}
#define UML_MCONSOLE_HELPTEXT \ #define UML_MCONSOLE_HELPTEXT \
"Commands: "Commands: \n\
version - Get kernel version version - Get kernel version \n\
help - Print this message help - Print this message \n\
halt - Halt UML halt - Halt UML \n\
reboot - Reboot UML reboot - Reboot UML \n\
config <dev>=<config> - Add a new device to UML; config <dev>=<config> - Add a new device to UML; \n\
same syntax as command line same syntax as command line \n\
config <dev> - Query the configuration of a device config <dev> - Query the configuration of a device \n\
remove <dev> - Remove a device from UML remove <dev> - Remove a device from UML \n\
sysrq <letter> - Performs the SysRq action controlled by the letter sysrq <letter> - Performs the SysRq action controlled by the letter \n\
cad - invoke the Ctl-Alt-Del handler cad - invoke the Ctl-Alt-Del handler \n\
stop - pause the UML; it will do nothing until it receives a 'go' stop - pause the UML; it will do nothing until it receives a 'go' \n\
go - continue the UML after a 'stop' go - continue the UML after a 'stop' \n\
log <string> - make UML enter <string> into the kernel log\n\
proc <file> - returns the contents of the UML's /proc/<file>\n\
" "
void mconsole_help(struct mc_request *req) void mconsole_help(struct mc_request *req)
...@@ -302,7 +397,7 @@ int mconsole_init(void) ...@@ -302,7 +397,7 @@ int mconsole_init(void)
if(umid_file_name("mconsole", file, sizeof(file))) return(-1); if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
snprintf(mconsole_socket_name, sizeof(file), "%s", file); snprintf(mconsole_socket_name, sizeof(file), "%s", file);
sock = create_unix_socket(file, sizeof(file)); sock = os_create_unix_socket(file, sizeof(file), 1);
if (sock < 0){ if (sock < 0){
printk("Failed to initialize management console\n"); printk("Failed to initialize management console\n");
return(1); return(1);
...@@ -344,11 +439,16 @@ static int write_proc_mconsole(struct file *file, const char *buffer, ...@@ -344,11 +439,16 @@ static int write_proc_mconsole(struct file *file, const char *buffer,
if(buf == NULL) if(buf == NULL)
return(-ENOMEM); return(-ENOMEM);
if(copy_from_user(buf, buffer, count)) if(copy_from_user(buf, buffer, count)){
return(-EFAULT); count = -EFAULT;
goto out;
}
buf[count] = '\0'; buf[count] = '\0';
mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count); mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
out:
kfree(buf);
return(count); return(count);
} }
......
/* /*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL * Licensed under the GPL
*/ */
...@@ -18,16 +18,18 @@ ...@@ -18,16 +18,18 @@
#include "umid.h" #include "umid.h"
static struct mconsole_command commands[] = { static struct mconsole_command commands[] = {
{ "version", mconsole_version, 1 }, { "version", mconsole_version, MCONSOLE_INTR },
{ "halt", mconsole_halt, 0 }, { "halt", mconsole_halt, MCONSOLE_PROC },
{ "reboot", mconsole_reboot, 0 }, { "reboot", mconsole_reboot, MCONSOLE_PROC },
{ "config", mconsole_config, 0 }, { "config", mconsole_config, MCONSOLE_PROC },
{ "remove", mconsole_remove, 0 }, { "remove", mconsole_remove, MCONSOLE_PROC },
{ "sysrq", mconsole_sysrq, 1 }, { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
{ "help", mconsole_help, 1 }, { "help", mconsole_help, MCONSOLE_INTR },
{ "cad", mconsole_cad, 1 }, { "cad", mconsole_cad, MCONSOLE_INTR },
{ "stop", mconsole_stop, 0 }, { "stop", mconsole_stop, MCONSOLE_PROC },
{ "go", mconsole_go, 1 }, { "go", mconsole_go, MCONSOLE_INTR },
{ "log", mconsole_log, MCONSOLE_INTR },
{ "proc", mconsole_proc, MCONSOLE_PROC },
}; };
/* Initialized in mconsole_init, which is an initcall */ /* Initialized in mconsole_init, which is an initcall */
...@@ -139,6 +141,7 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more) ...@@ -139,6 +141,7 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more)
memcpy(reply.data, str, len); memcpy(reply.data, str, len);
reply.data[len] = '\0'; reply.data[len] = '\0';
total -= len; total -= len;
str += len;
reply.len = len + 1; reply.len = len + 1;
len = sizeof(reply) + reply.len - sizeof(reply.data); len = sizeof(reply) + reply.len - sizeof(reply.data);
......
...@@ -120,7 +120,10 @@ static int __init mmapper_init(void) ...@@ -120,7 +120,10 @@ static int __init mmapper_init(void)
printk(KERN_INFO "Mapper v0.1\n"); printk(KERN_INFO "Mapper v0.1\n");
v_buf = (char *) find_iomem("mmapper", &mmapper_size); v_buf = (char *) find_iomem("mmapper", &mmapper_size);
if(mmapper_size == 0) return(0); if(mmapper_size == 0){
printk(KERN_ERR "mmapper_init - find_iomem failed\n");
return(0);
}
p_buf = __pa(v_buf); p_buf = __pa(v_buf);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "mconsole_kern.h" #include "mconsole_kern.h"
#include "init.h" #include "init.h"
#include "irq_user.h" #include "irq_user.h"
#include "irq_kern.h"
static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
LIST_HEAD(opened); LIST_HEAD(opened);
...@@ -37,7 +38,8 @@ static int uml_net_rx(struct net_device *dev) ...@@ -37,7 +38,8 @@ static int uml_net_rx(struct net_device *dev)
struct sk_buff *skb; struct sk_buff *skb;
/* If we can't allocate memory, try again next round. */ /* If we can't allocate memory, try again next round. */
if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { skb = dev_alloc_skb(dev->mtu);
if (skb == NULL) {
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
return 0; return 0;
} }
...@@ -61,14 +63,14 @@ static int uml_net_rx(struct net_device *dev) ...@@ -61,14 +63,14 @@ static int uml_net_rx(struct net_device *dev)
return pkt_len; return pkt_len;
} }
void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct net_device *dev = dev_id; struct net_device *dev = dev_id;
struct uml_net_private *lp = dev->priv; struct uml_net_private *lp = dev->priv;
int err; int err;
if(!netif_running(dev)) if(!netif_running(dev))
return; return(IRQ_NONE);
spin_lock(&lp->lock); spin_lock(&lp->lock);
while((err = uml_net_rx(dev)) > 0) ; while((err = uml_net_rx(dev)) > 0) ;
...@@ -83,6 +85,7 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -83,6 +85,7 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
out: out:
spin_unlock(&lp->lock); spin_unlock(&lp->lock);
return(IRQ_HANDLED);
} }
static int uml_net_open(struct net_device *dev) static int uml_net_open(struct net_device *dev)
...@@ -250,37 +253,6 @@ void uml_net_user_timer_expire(unsigned long _conn) ...@@ -250,37 +253,6 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif #endif
} }
/*
* default do nothing hard header packet routines for struct net_device init.
* real ethernet transports will overwrite with real routines.
*/
static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
return(0); /* no change */
}
static int uml_net_rebuild_header(struct sk_buff *skb)
{
return(0); /* ignore */
}
static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
{
return(-1); /* fail */
}
static void uml_net_header_cache_update(struct hh_cache *hh,
struct net_device *dev, unsigned char * haddr)
{
/* ignore */
}
static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
{
return(0); /* nothing */
}
static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
static struct list_head devices = LIST_HEAD_INIT(devices); static struct list_head devices = LIST_HEAD_INIT(devices);
...@@ -290,7 +262,7 @@ static int eth_configure(int n, void *init, char *mac, ...@@ -290,7 +262,7 @@ static int eth_configure(int n, void *init, char *mac,
struct uml_net *device; struct uml_net *device;
struct net_device *dev; struct net_device *dev;
struct uml_net_private *lp; struct uml_net_private *lp;
int err, size; int save, err, size;
size = transport->private_size + sizeof(struct uml_net_private) + size = transport->private_size + sizeof(struct uml_net_private) +
sizeof(((struct uml_net_private *) 0)->user); sizeof(((struct uml_net_private *) 0)->user);
...@@ -332,12 +304,6 @@ static int eth_configure(int n, void *init, char *mac, ...@@ -332,12 +304,6 @@ static int eth_configure(int n, void *init, char *mac,
snprintf(dev->name, sizeof(dev->name), "eth%d", n); snprintf(dev->name, sizeof(dev->name), "eth%d", n);
device->dev = dev; device->dev = dev;
dev->hard_header = uml_net_hard_header;
dev->rebuild_header = uml_net_rebuild_header;
dev->hard_header_cache = uml_net_header_cache;
dev->header_cache_update= uml_net_header_cache_update;
dev->hard_header_parse = uml_net_header_parse;
(*transport->kern->init)(dev, init); (*transport->kern->init)(dev, init);
dev->mtu = transport->user->max_packet; dev->mtu = transport->user->max_packet;
...@@ -364,21 +330,29 @@ static int eth_configure(int n, void *init, char *mac, ...@@ -364,21 +330,29 @@ static int eth_configure(int n, void *init, char *mac,
} }
lp = dev->priv; lp = dev->priv;
INIT_LIST_HEAD(&lp->list); /* lp.user is the first four bytes of the transport data, which
spin_lock_init(&lp->lock); * has already been initialized. This structure assignment will
lp->dev = dev; * overwrite that, so we make sure that .user gets overwritten with
lp->fd = -1; * what it already has.
lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }; */
lp->have_mac = device->have_mac; save = lp->user[0];
lp->protocol = transport->kern->protocol; *lp = ((struct uml_net_private)
lp->open = transport->user->open; { .list = LIST_HEAD_INIT(lp->list),
lp->close = transport->user->close; .lock = SPIN_LOCK_UNLOCKED,
lp->remove = transport->user->remove; .dev = dev,
lp->read = transport->kern->read; .fd = -1,
lp->write = transport->kern->write; .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
lp->add_address = transport->user->add_address; .have_mac = device->have_mac,
lp->delete_address = transport->user->delete_address; .protocol = transport->kern->protocol,
lp->set_mtu = transport->user->set_mtu; .open = transport->user->open,
.close = transport->user->close,
.remove = transport->user->remove,
.read = transport->kern->read,
.write = transport->kern->write,
.add_address = transport->user->add_address,
.delete_address = transport->user->delete_address,
.set_mtu = transport->user->set_mtu,
.user = { save } });
init_timer(&lp->tl); init_timer(&lp->tl);
lp->tl.function = uml_net_user_timer_expire; lp->tl.function = uml_net_user_timer_expire;
...@@ -611,7 +585,8 @@ static int net_remove(char *str) ...@@ -611,7 +585,8 @@ static int net_remove(char *str)
unregister_netdev(dev); unregister_netdev(dev);
list_del(&device->list); list_del(&device->list);
free_netdev(device); kfree(device);
free_netdev(dev);
return(0); return(0);
} }
......
...@@ -26,8 +26,7 @@ int tap_open_common(void *dev, char *gate_addr) ...@@ -26,8 +26,7 @@ int tap_open_common(void *dev, char *gate_addr)
if(gate_addr == NULL) return(0); if(gate_addr == NULL) return(0);
if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
&tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
printk("Invalid tap IP address - '%s'\n", printk("Invalid tap IP address - '%s'\n", gate_addr);
gate_addr);
return(-EINVAL); return(-EINVAL);
} }
return(0); return(0);
...@@ -60,18 +59,18 @@ void read_output(int fd, char *output, int len) ...@@ -60,18 +59,18 @@ void read_output(int fd, char *output, int len)
} }
*output = '\0'; *output = '\0';
if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){ n = os_read_file(fd, &remain, sizeof(remain));
printk("read_output - read of length failed, errno = %d\n", if(n != sizeof(remain)){
errno); printk("read_output - read of length failed, err = %d\n", -n);
return; return;
} }
while(remain != 0){ while(remain != 0){
n = (remain < len) ? remain : len; n = (remain < len) ? remain : len;
actual = read(fd, output, n); actual = os_read_file(fd, output, n);
if(actual != n){ if(actual != n){
printk("read_output - read of data failed, " printk("read_output - read of data failed, "
"errno = %d\n", errno); "err = %d\n", -actual);
return; return;
} }
remain -= actual; remain -= actual;
...@@ -83,13 +82,12 @@ int net_read(int fd, void *buf, int len) ...@@ -83,13 +82,12 @@ int net_read(int fd, void *buf, int len)
{ {
int n; int n;
while(((n = read(fd, buf, len)) < 0) && (errno == EINTR)) ; n = os_read_file(fd, buf, len);
if(n < 0){ if(n == -EAGAIN)
if(errno == EAGAIN) return(0); return(0);
return(-errno); else if(n == 0)
} return(-ENOTCONN);
else if(n == 0) return(-ENOTCONN);
return(n); return(n);
} }
...@@ -112,13 +110,13 @@ int net_write(int fd, void *buf, int len) ...@@ -112,13 +110,13 @@ int net_write(int fd, void *buf, int len)
{ {
int n; int n;
while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ; n = os_write_file(fd, buf, len);
if(n < 0){
if(errno == EAGAIN) return(0); if(n == -EAGAIN)
return(-errno); return(0);
} else if(n == 0)
else if(n == 0) return(-ENOTCONN); return(-ENOTCONN);
return(n); return(n);
} }
int net_send(int fd, void *buf, int len) int net_send(int fd, void *buf, int len)
...@@ -157,7 +155,7 @@ static void change_pre_exec(void *arg) ...@@ -157,7 +155,7 @@ static void change_pre_exec(void *arg)
{ {
struct change_pre_exec_data *data = arg; struct change_pre_exec_data *data = arg;
close(data->close_me); os_close_file(data->close_me);
dup2(data->stdout, 1); dup2(data->stdout, 1);
} }
...@@ -167,15 +165,15 @@ static int change_tramp(char **argv, char *output, int output_len) ...@@ -167,15 +165,15 @@ static int change_tramp(char **argv, char *output, int output_len)
struct change_pre_exec_data pe_data; struct change_pre_exec_data pe_data;
err = os_pipe(fds, 1, 0); err = os_pipe(fds, 1, 0);
if(err){ if(err < 0){
printk("change_tramp - pipe failed, errno = %d\n", -err); printk("change_tramp - pipe failed, err = %d\n", -err);
return(err); return(err);
} }
pe_data.close_me = fds[0]; pe_data.close_me = fds[0];
pe_data.stdout = fds[1]; pe_data.stdout = fds[1];
pid = run_helper(change_pre_exec, &pe_data, argv, NULL); pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
close(fds[1]); os_close_file(fds[1]);
read_output(fds[0], output, output_len); read_output(fds[0], output, output_len);
waitpid(pid, NULL, 0); waitpid(pid, NULL, 0);
return(pid); return(pid);
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include "chan_user.h" #include "chan_user.h"
#include "os.h" #include "os.h"
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "linux/list.h" #include "linux/list.h"
#include "linux/sched.h" #include "linux/sched.h"
#include "linux/slab.h" #include "linux/slab.h"
#include "linux/interrupt.h"
#include "linux/irq.h" #include "linux/irq.h"
#include "linux/spinlock.h" #include "linux/spinlock.h"
#include "linux/errno.h" #include "linux/errno.h"
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include "kern_util.h" #include "kern_util.h"
#include "kern.h" #include "kern.h"
#include "irq_user.h" #include "irq_user.h"
#include "irq_kern.h"
#include "port.h" #include "port.h"
#include "init.h" #include "init.h"
#include "os.h" #include "os.h"
...@@ -38,21 +40,21 @@ struct port_dev { ...@@ -38,21 +40,21 @@ struct port_dev {
struct connection { struct connection {
struct list_head list; struct list_head list;
int fd; int fd;
int helper_pid; int helper_pid;
int socket[2]; int socket[2];
int telnetd_pid; int telnetd_pid;
struct port_list *port; struct port_list *port;
}; };
static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
{ {
struct connection *conn = data; struct connection *conn = data;
int fd; int fd;
fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
if(fd < 0){ if(fd < 0){
if(fd == -EAGAIN) if(fd == -EAGAIN)
return; return(IRQ_NONE);
printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
-fd); -fd);
...@@ -65,6 +67,7 @@ static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) ...@@ -65,6 +67,7 @@ static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
list_add(&conn->list, &conn->port->connections); list_add(&conn->list, &conn->port->connections);
up(&conn->port->sem); up(&conn->port->sem);
return(IRQ_HANDLED);
} }
static int port_accept(struct port_list *port) static int port_accept(struct port_list *port)
...@@ -102,8 +105,7 @@ static int port_accept(struct port_list *port) ...@@ -102,8 +105,7 @@ static int port_accept(struct port_list *port)
} }
list_add(&conn->list, &port->pending); list_add(&conn->list, &port->pending);
ret = 1; return(1);
goto out;
out_free: out_free:
kfree(conn); kfree(conn);
...@@ -138,12 +140,13 @@ void port_work_proc(void *unused) ...@@ -138,12 +140,13 @@ void port_work_proc(void *unused)
DECLARE_WORK(port_work, port_work_proc, NULL); DECLARE_WORK(port_work, port_work_proc, NULL);
static void port_interrupt(int irq, void *data, struct pt_regs *regs) static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
{ {
struct port_list *port = data; struct port_list *port = data;
port->has_connection = 1; port->has_connection = 1;
schedule_work(&port_work); schedule_work(&port_work);
return(IRQ_HANDLED);
} }
void *port_data(int port_num) void *port_data(int port_num)
......
...@@ -47,10 +47,12 @@ void *port_init(char *str, int device, struct chan_opts *opts) ...@@ -47,10 +47,12 @@ void *port_init(char *str, int device, struct chan_opts *opts)
return(NULL); return(NULL);
} }
if((kern_data = port_data(port)) == NULL) kern_data = port_data(port);
if(kern_data == NULL)
return(NULL); return(NULL);
if((data = um_kmalloc(sizeof(*data))) == NULL) data = um_kmalloc(sizeof(*data));
if(data == NULL)
goto err; goto err;
*data = ((struct port_chan) { .raw = opts->raw, *data = ((struct port_chan) { .raw = opts->raw,
...@@ -90,7 +92,7 @@ void port_close(int fd, void *d) ...@@ -90,7 +92,7 @@ void port_close(int fd, void *d)
struct port_chan *data = d; struct port_chan *data = d;
port_remove_dev(data->kernel_data); port_remove_dev(data->kernel_data);
close(fd); os_close_file(fd);
} }
int port_console_write(int fd, const char *buf, int n, void *d) int port_console_write(int fd, const char *buf, int n, void *d)
...@@ -130,11 +132,15 @@ int port_listen_fd(int port) ...@@ -130,11 +132,15 @@ int port_listen_fd(int port)
goto out; goto out;
} }
if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){ if(listen(fd, 1) < 0){
err = -errno; err = -errno;
goto out; goto out;
} }
err = os_set_fd_block(fd, 0);
if(err < 0)
goto out;
return(fd); return(fd);
out: out:
os_close_file(fd); os_close_file(fd);
...@@ -153,10 +159,10 @@ void port_pre_exec(void *arg) ...@@ -153,10 +159,10 @@ void port_pre_exec(void *arg)
dup2(data->sock_fd, 0); dup2(data->sock_fd, 0);
dup2(data->sock_fd, 1); dup2(data->sock_fd, 1);
dup2(data->sock_fd, 2); dup2(data->sock_fd, 2);
close(data->sock_fd); os_close_file(data->sock_fd);
dup2(data->pipe_fd, 3); dup2(data->pipe_fd, 3);
os_shutdown_socket(3, 1, 0); os_shutdown_socket(3, 1, 0);
close(data->pipe_fd); os_close_file(data->pipe_fd);
} }
int port_connection(int fd, int *socket, int *pid_out) int port_connection(int fd, int *socket, int *pid_out)
...@@ -166,11 +172,12 @@ int port_connection(int fd, int *socket, int *pid_out) ...@@ -166,11 +172,12 @@ int port_connection(int fd, int *socket, int *pid_out)
"/usr/lib/uml/port-helper", NULL }; "/usr/lib/uml/port-helper", NULL };
struct port_pre_exec_data data; struct port_pre_exec_data data;
if((new = os_accept_connection(fd)) < 0) new = os_accept_connection(fd);
return(-errno); if(new < 0)
return(new);
err = os_pipe(socket, 0, 0); err = os_pipe(socket, 0, 0);
if(err) if(err < 0)
goto out_close; goto out_close;
data = ((struct port_pre_exec_data) data = ((struct port_pre_exec_data)
...@@ -186,11 +193,11 @@ int port_connection(int fd, int *socket, int *pid_out) ...@@ -186,11 +193,11 @@ int port_connection(int fd, int *socket, int *pid_out)
out_shutdown: out_shutdown:
os_shutdown_socket(socket[0], 1, 1); os_shutdown_socket(socket[0], 1, 1);
close(socket[0]); os_close_file(socket[0]);
os_shutdown_socket(socket[1], 1, 1); os_shutdown_socket(socket[1], 1, 1);
close(socket[1]); os_close_file(socket[1]);
out_close: out_close:
close(new); os_close_file(new);
return(err); return(err);
} }
......
...@@ -7,12 +7,12 @@ ...@@ -7,12 +7,12 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <termios.h> #include <termios.h>
#include "chan_user.h" #include "chan_user.h"
#include "user.h" #include "user.h"
#include "user_util.h" #include "user_util.h"
#include "kern_util.h" #include "kern_util.h"
#include "os.h"
struct pty_chan { struct pty_chan {
void (*announce)(char *dev_name, int dev); void (*announce)(char *dev_name, int dev);
...@@ -26,7 +26,8 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts) ...@@ -26,7 +26,8 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts)
{ {
struct pty_chan *data; struct pty_chan *data;
if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); data = um_kmalloc(sizeof(*data));
if(data == NULL) return(NULL);
*data = ((struct pty_chan) { .announce = opts->announce, *data = ((struct pty_chan) { .announce = opts->announce,
.dev = device, .dev = device,
.raw = opts->raw }); .raw = opts->raw });
...@@ -39,7 +40,8 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) ...@@ -39,7 +40,8 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out)
char *dev; char *dev;
int fd; int fd;
if((fd = get_pty()) < 0){ fd = get_pty();
if(fd < 0){
printk("open_pts : Failed to open pts\n"); printk("open_pts : Failed to open pts\n");
return(-errno); return(-errno);
} }
...@@ -57,29 +59,27 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) ...@@ -57,29 +59,27 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out)
int getmaster(char *line) int getmaster(char *line)
{ {
struct stat stb;
char *pty, *bank, *cp; char *pty, *bank, *cp;
int master; int master, err;
pty = &line[strlen("/dev/ptyp")]; pty = &line[strlen("/dev/ptyp")];
for (bank = "pqrs"; *bank; bank++) { for (bank = "pqrs"; *bank; bank++) {
line[strlen("/dev/pty")] = *bank; line[strlen("/dev/pty")] = *bank;
*pty = '0'; *pty = '0';
if (stat(line, &stb) < 0) if (os_stat_file(line, NULL) < 0)
break; break;
for (cp = "0123456789abcdef"; *cp; cp++) { for (cp = "0123456789abcdef"; *cp; cp++) {
*pty = *cp; *pty = *cp;
master = open(line, O_RDWR); master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
if (master >= 0) { if (master >= 0) {
char *tp = &line[strlen("/dev/")]; char *tp = &line[strlen("/dev/")];
int ok;
/* verify slave side is usable */ /* verify slave side is usable */
*tp = 't'; *tp = 't';
ok = access(line, R_OK|W_OK) == 0; err = os_access(line, OS_ACC_RW_OK);
*tp = 'p'; *tp = 'p';
if (ok) return(master); if(err == 0) return(master);
(void) close(master); (void) os_close_file(master);
} }
} }
} }
......
...@@ -4,11 +4,9 @@ ...@@ -4,11 +4,9 @@
#include <stddef.h> #include <stddef.h>
#include <sched.h> #include <sched.h>
#include <string.h> #include <string.h>
#include <sys/fcntl.h>
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/termios.h> #include <sys/termios.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/signal.h> #include <sys/signal.h>
#include "user_util.h" #include "user_util.h"
#include "kern_util.h" #include "kern_util.h"
...@@ -65,9 +63,9 @@ static void slip_pre_exec(void *arg) ...@@ -65,9 +63,9 @@ static void slip_pre_exec(void *arg)
{ {
struct slip_pre_exec_data *data = arg; struct slip_pre_exec_data *data = arg;
if(data->stdin != -1) dup2(data->stdin, 0); if(data->stdin >= 0) dup2(data->stdin, 0);
dup2(data->stdout, 1); dup2(data->stdout, 1);
if(data->close_me != -1) close(data->close_me); if(data->close_me >= 0) os_close_file(data->close_me);
} }
static int slip_tramp(char **argv, int fd) static int slip_tramp(char **argv, int fd)
...@@ -77,8 +75,8 @@ static int slip_tramp(char **argv, int fd) ...@@ -77,8 +75,8 @@ static int slip_tramp(char **argv, int fd)
int status, pid, fds[2], err, output_len; int status, pid, fds[2], err, output_len;
err = os_pipe(fds, 1, 0); err = os_pipe(fds, 1, 0);
if(err){ if(err < 0){
printk("slip_tramp : pipe failed, errno = %d\n", -err); printk("slip_tramp : pipe failed, err = %d\n", -err);
return(err); return(err);
} }
...@@ -96,7 +94,7 @@ static int slip_tramp(char **argv, int fd) ...@@ -96,7 +94,7 @@ static int slip_tramp(char **argv, int fd)
printk("slip_tramp : failed to allocate output " printk("slip_tramp : failed to allocate output "
"buffer\n"); "buffer\n");
close(fds[1]); os_close_file(fds[1]);
read_output(fds[0], output, output_len); read_output(fds[0], output, output_len);
if(output != NULL){ if(output != NULL){
printk("%s", output); printk("%s", output);
...@@ -105,7 +103,7 @@ static int slip_tramp(char **argv, int fd) ...@@ -105,7 +103,7 @@ static int slip_tramp(char **argv, int fd)
if(waitpid(pid, &status, 0) < 0) err = errno; if(waitpid(pid, &status, 0) < 0) err = errno;
else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
printk("'%s' didn't exit with status 0\n", argv[0]); printk("'%s' didn't exit with status 0\n", argv[0]);
err = EINVAL; err = -EINVAL;
} }
} }
return(err); return(err);
...@@ -118,15 +116,17 @@ static int slip_open(void *data) ...@@ -118,15 +116,17 @@ static int slip_open(void *data)
char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
NULL }; NULL };
int sfd, mfd, disc, sencap, err; int sfd, mfd, err;
if((mfd = get_pty()) < 0){ mfd = get_pty();
printk("umn : Failed to open pty\n"); if(mfd < 0){
return(-1); printk("umn : Failed to open pty, err = %d\n", -mfd);
return(mfd);
} }
if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){ sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
printk("Couldn't open tty for slip line\n"); if(sfd < 0){
return(-1); printk("Couldn't open tty for slip line, err = %d\n", -sfd);
return(sfd);
} }
if(set_up_tty(sfd)) return(-1); if(set_up_tty(sfd)) return(-1);
pri->slave = sfd; pri->slave = sfd;
...@@ -138,28 +138,23 @@ static int slip_open(void *data) ...@@ -138,28 +138,23 @@ static int slip_open(void *data)
err = slip_tramp(argv, sfd); err = slip_tramp(argv, sfd);
if(err != 0){ if(err < 0){
printk("slip_tramp failed - errno = %d\n", err); printk("slip_tramp failed - err = %d\n", -err);
return(-err); return(err);
} }
if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){ err = os_get_ifname(pri->slave, pri->name);
printk("SIOCGIFNAME failed, errno = %d\n", errno); if(err < 0){
return(-errno); printk("get_ifname failed, err = %d\n", -err);
return(err);
} }
iter_addresses(pri->dev, open_addr, pri->name); iter_addresses(pri->dev, open_addr, pri->name);
} }
else { else {
disc = N_SLIP; err = os_set_slip(sfd);
if(ioctl(sfd, TIOCSETD, &disc) < 0){ if(err < 0){
printk("Failed to set slip line discipline - " printk("Failed to set slip discipline encapsulation - "
"errno = %d\n", errno); "err = %d\n", -err);
return(-errno); return(err);
}
sencap = 0;
if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
printk("Failed to set slip encapsulation - "
"errno = %d\n", errno);
return(-errno);
} }
} }
return(mfd); return(mfd);
...@@ -181,9 +176,9 @@ static void slip_close(int fd, void *data) ...@@ -181,9 +176,9 @@ static void slip_close(int fd, void *data)
err = slip_tramp(argv, -1); err = slip_tramp(argv, -1);
if(err != 0) if(err != 0)
printk("slip_tramp failed - errno = %d\n", err); printk("slip_tramp failed - errno = %d\n", -err);
close(fd); os_close_file(fd);
close(pri->slave); os_close_file(pri->slave);
pri->slave = -1; pri->slave = -1;
} }
...@@ -243,7 +238,7 @@ static void slip_add_addr(unsigned char *addr, unsigned char *netmask, ...@@ -243,7 +238,7 @@ static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
{ {
struct slip_data *pri = data; struct slip_data *pri = data;
if(pri->slave == -1) return; if(pri->slave < 0) return;
open_addr(addr, netmask, pri->name); open_addr(addr, netmask, pri->name);
} }
...@@ -252,7 +247,7 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask, ...@@ -252,7 +247,7 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
{ {
struct slip_data *pri = data; struct slip_data *pri = data;
if(pri->slave == -1) return; if(pri->slave < 0) return;
close_addr(addr, netmask, pri->name); close_addr(addr, netmask, pri->name);
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include <stddef.h> #include <stddef.h>
#include <sched.h> #include <sched.h>
#include <string.h> #include <string.h>
#include <sys/fcntl.h>
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/signal.h> #include <sys/signal.h>
...@@ -48,15 +47,15 @@ static int slirp_tramp(char **argv, int fd) ...@@ -48,15 +47,15 @@ static int slirp_tramp(char **argv, int fd)
return(pid); return(pid);
} }
/* XXX This is just a trivial wrapper around os_pipe */
static int slirp_datachan(int *mfd, int *sfd) static int slirp_datachan(int *mfd, int *sfd)
{ {
int fds[2], err; int fds[2], err;
err = os_pipe(fds, 1, 1); err = os_pipe(fds, 1, 1);
if(err){ if(err < 0){
printk("slirp_datachan: Failed to open pipe, errno = %d\n", printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
-err);
return(err); return(err);
} }
...@@ -77,7 +76,7 @@ static int slirp_open(void *data) ...@@ -77,7 +76,7 @@ static int slirp_open(void *data)
pid = slirp_tramp(pri->argw.argv, sfd); pid = slirp_tramp(pri->argw.argv, sfd);
if(pid < 0){ if(pid < 0){
printk("slirp_tramp failed - errno = %d\n", pid); printk("slirp_tramp failed - errno = %d\n", -pid);
os_close_file(sfd); os_close_file(sfd);
os_close_file(mfd); os_close_file(mfd);
return(pid); return(pid);
...@@ -97,8 +96,8 @@ static void slirp_close(int fd, void *data) ...@@ -97,8 +96,8 @@ static void slirp_close(int fd, void *data)
struct slirp_data *pri = data; struct slirp_data *pri = data;
int status,err; int status,err;
close(fd); os_close_file(fd);
close(pri->slave); os_close_file(pri->slave);
pri->slave = -1; pri->slave = -1;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "linux/major.h" #include "linux/major.h"
#include "linux/mm.h" #include "linux/mm.h"
#include "linux/init.h" #include "linux/init.h"
#include "linux/console.h"
#include "asm/termbits.h" #include "asm/termbits.h"
#include "asm/irq.h" #include "asm/irq.h"
#include "line.h" #include "line.h"
...@@ -53,8 +54,9 @@ static int ssl_remove(char *str); ...@@ -53,8 +54,9 @@ static int ssl_remove(char *str);
static struct line_driver driver = { static struct line_driver driver = {
.name = "UML serial line", .name = "UML serial line",
.devfs_name = "tts/%d", .device_name = "ttS",
.major = TTYAUX_MAJOR, .devfs_name = "tts/",
.major = TTY_MAJOR,
.minor_start = 64, .minor_start = 64,
.type = TTY_DRIVER_TYPE_SERIAL, .type = TTY_DRIVER_TYPE_SERIAL,
.subtype = 0, .subtype = 0,
...@@ -149,6 +151,9 @@ static int ssl_ioctl(struct tty_struct *tty, struct file * file, ...@@ -149,6 +151,9 @@ static int ssl_ioctl(struct tty_struct *tty, struct file * file,
case TCSETSW: case TCSETSW:
case TCGETA: case TCGETA:
case TIOCMGET: case TIOCMGET:
case TCSBRK:
case TCSBRKP:
case TIOCMSET:
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;
break; break;
default: default:
...@@ -212,6 +217,37 @@ static struct tty_operations ssl_ops = { ...@@ -212,6 +217,37 @@ static struct tty_operations ssl_ops = {
*/ */
static int ssl_init_done = 0; static int ssl_init_done = 0;
static void ssl_console_write(struct console *c, const char *string,
unsigned len)
{
struct line *line = &serial_lines[c->index];
if(ssl_init_done)
down(&line->sem);
console_write_chan(&line->chan_list, string, len);
if(ssl_init_done)
up(&line->sem);
}
static struct tty_driver *ssl_console_device(struct console *c, int *index)
{
*index = c->index;
return ssl_driver;
}
static int ssl_console_setup(struct console *co, char *options)
{
return(0);
}
static struct console ssl_cons = {
name: "ttyS",
write: ssl_console_write,
device: ssl_console_device,
setup: ssl_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
int ssl_init(void) int ssl_init(void)
{ {
char *new_title; char *new_title;
...@@ -227,17 +263,18 @@ int ssl_init(void) ...@@ -227,17 +263,18 @@ int ssl_init(void)
new_title = add_xterm_umid(opts.xterm_title); new_title = add_xterm_umid(opts.xterm_title);
if(new_title != NULL) opts.xterm_title = new_title; if(new_title != NULL) opts.xterm_title = new_title;
register_console(&ssl_cons);
ssl_init_done = 1; ssl_init_done = 1;
return(0); return(0);
} }
__initcall(ssl_init); late_initcall(ssl_init);
static int ssl_chan_setup(char *str) static int ssl_chan_setup(char *str)
{ {
line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]), return(line_setup(serial_lines,
str, 1); sizeof(serial_lines)/sizeof(serial_lines[0]),
return(1); str, 1));
} }
__setup("ssl", ssl_chan_setup); __setup("ssl", ssl_chan_setup);
......
...@@ -83,7 +83,8 @@ static int con_remove(char *str); ...@@ -83,7 +83,8 @@ static int con_remove(char *str);
static struct line_driver driver = { static struct line_driver driver = {
.name = "UML console", .name = "UML console",
.devfs_name = "vc/%d", .device_name = "tty",
.devfs_name = "vc/",
.major = TTY_MAJOR, .major = TTY_MAJOR,
.minor_start = 0, .minor_start = 0,
.type = TTY_DRIVER_TYPE_CONSOLE, .type = TTY_DRIVER_TYPE_CONSOLE,
...@@ -159,6 +160,15 @@ static int chars_in_buffer(struct tty_struct *tty) ...@@ -159,6 +160,15 @@ static int chars_in_buffer(struct tty_struct *tty)
static int con_init_done = 0; static int con_init_done = 0;
static struct tty_operations console_ops = {
.open = con_open,
.close = con_close,
.write = con_write,
.chars_in_buffer = chars_in_buffer,
.set_termios = set_termios,
.write_room = line_write_room,
};
int stdio_init(void) int stdio_init(void)
{ {
char *new_title; char *new_title;
...@@ -166,7 +176,8 @@ int stdio_init(void) ...@@ -166,7 +176,8 @@ int stdio_init(void)
printk(KERN_INFO "Initializing stdio console driver\n"); printk(KERN_INFO "Initializing stdio console driver\n");
console_driver = line_register_devfs(&console_lines, &driver, console_driver = line_register_devfs(&console_lines, &driver,
&console_ops, vts, sizeof(vts)/sizeof(vts[0])); &console_ops, vts,
sizeof(vts)/sizeof(vts[0]));
lines_init(vts, sizeof(vts)/sizeof(vts[0])); lines_init(vts, sizeof(vts)/sizeof(vts[0]));
...@@ -178,24 +189,19 @@ int stdio_init(void) ...@@ -178,24 +189,19 @@ int stdio_init(void)
return(0); return(0);
} }
__initcall(stdio_init); late_initcall(stdio_init);
static void console_write(struct console *console, const char *string, static void console_write(struct console *console, const char *string,
unsigned len) unsigned len)
{ {
if(con_init_done) down(&vts[console->index].sem); struct line *line = &vts[console->index];
console_write_chan(&vts[console->index].chan_list, string, len);
if(con_init_done) up(&vts[console->index].sem);
}
static struct tty_operations console_ops = { if(con_init_done)
.open = con_open, down(&line->sem);
.close = con_close, console_write_chan(&line->chan_list, string, len);
.write = con_write, if(con_init_done)
.chars_in_buffer = chars_in_buffer, up(&line->sem);
.set_termios = set_termios, }
.write_room = line_write_room,
};
static struct tty_driver *console_device(struct console *c, int *index) static struct tty_driver *console_device(struct console *c, int *index)
{ {
...@@ -208,22 +214,28 @@ static int console_setup(struct console *co, char *options) ...@@ -208,22 +214,28 @@ static int console_setup(struct console *co, char *options)
return(0); return(0);
} }
static struct console stdiocons = INIT_CONSOLE("tty", console_write, static struct console stdiocons = {
console_device, console_setup, name: "tty",
CON_PRINTBUFFER); write: console_write,
device: console_device,
setup: console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
static void __init stdio_console_init(void) static int __init stdio_console_init(void)
{ {
INIT_LIST_HEAD(&vts[0].chan_list); INIT_LIST_HEAD(&vts[0].chan_list);
list_add(&init_console_chan.list, &vts[0].chan_list); list_add(&init_console_chan.list, &vts[0].chan_list);
register_console(&stdiocons); register_console(&stdiocons);
return(0);
} }
console_initcall(stdio_console_init); console_initcall(stdio_console_init);
static int console_chan_setup(char *str) static int console_chan_setup(char *str)
{ {
line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
return(1);
} }
__setup("con", console_chan_setup); __setup("con", console_chan_setup);
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include <stdio.h> #include <stdio.h>
#include <termios.h> #include <termios.h>
#include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include "chan_user.h" #include "chan_user.h"
...@@ -30,7 +29,8 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts) ...@@ -30,7 +29,8 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts)
} }
str++; str++;
if((data = um_kmalloc(sizeof(*data))) == NULL) data = um_kmalloc(sizeof(*data));
if(data == NULL)
return(NULL); return(NULL);
*data = ((struct tty_chan) { .dev = str, *data = ((struct tty_chan) { .dev = str,
.raw = opts->raw }); .raw = opts->raw });
......
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <termios.h> #include <termios.h>
#include <signal.h> #include <signal.h>
#include <sched.h> #include <sched.h>
...@@ -36,7 +35,8 @@ void *xterm_init(char *str, int device, struct chan_opts *opts) ...@@ -36,7 +35,8 @@ void *xterm_init(char *str, int device, struct chan_opts *opts)
{ {
struct xterm_chan *data; struct xterm_chan *data;
if((data = malloc(sizeof(*data))) == NULL) return(NULL); data = malloc(sizeof(*data));
if(data == NULL) return(NULL);
*data = ((struct xterm_chan) { .pid = -1, *data = ((struct xterm_chan) { .pid = -1,
.helper_pid = -1, .helper_pid = -1,
.device = device, .device = device,
...@@ -93,7 +93,7 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) ...@@ -93,7 +93,7 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out)
"/usr/lib/uml/port-helper", "-uml-socket", "/usr/lib/uml/port-helper", "-uml-socket",
file, NULL }; file, NULL };
if(access(argv[4], X_OK)) if(os_access(argv[4], OS_ACC_X_OK) < 0)
argv[4] = "port-helper"; argv[4] = "port-helper";
fd = mkstemp(file); fd = mkstemp(file);
...@@ -106,13 +106,13 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) ...@@ -106,13 +106,13 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out)
printk("xterm_open : unlink failed, errno = %d\n", errno); printk("xterm_open : unlink failed, errno = %d\n", errno);
return(-errno); return(-errno);
} }
close(fd); os_close_file(fd);
fd = create_unix_socket(file, sizeof(file)); fd = os_create_unix_socket(file, sizeof(file), 1);
if(fd < 0){ if(fd < 0){
printk("xterm_open : create_unix_socket failed, errno = %d\n", printk("xterm_open : create_unix_socket failed, errno = %d\n",
-fd); -fd);
return(-fd); return(fd);
} }
sprintf(title, data->title, data->device); sprintf(title, data->title, data->device);
...@@ -128,15 +128,16 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) ...@@ -128,15 +128,16 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out)
if(data->direct_rcv) if(data->direct_rcv)
new = os_rcv_fd(fd, &data->helper_pid); new = os_rcv_fd(fd, &data->helper_pid);
else { else {
if((err = os_set_fd_block(fd, 0)) != 0){ err = os_set_fd_block(fd, 0);
if(err < 0){
printk("xterm_open : failed to set descriptor " printk("xterm_open : failed to set descriptor "
"non-blocking, errno = %d\n", err); "non-blocking, err = %d\n", -err);
return(err); return(err);
} }
new = xterm_fd(fd, &data->helper_pid); new = xterm_fd(fd, &data->helper_pid);
} }
if(new < 0){ if(new < 0){
printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new); printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
goto out; goto out;
} }
...@@ -160,7 +161,7 @@ void xterm_close(int fd, void *d) ...@@ -160,7 +161,7 @@ void xterm_close(int fd, void *d)
if(data->helper_pid != -1) if(data->helper_pid != -1)
os_kill_process(data->helper_pid, 0); os_kill_process(data->helper_pid, 0);
data->helper_pid = -1; data->helper_pid = -1;
close(fd); os_close_file(fd);
} }
void xterm_free(void *d) void xterm_free(void *d)
......
...@@ -5,9 +5,12 @@ ...@@ -5,9 +5,12 @@
#include "linux/errno.h" #include "linux/errno.h"
#include "linux/slab.h" #include "linux/slab.h"
#include "linux/signal.h"
#include "linux/interrupt.h"
#include "asm/semaphore.h" #include "asm/semaphore.h"
#include "asm/irq.h" #include "asm/irq.h"
#include "irq_user.h" #include "irq_user.h"
#include "irq_kern.h"
#include "kern_util.h" #include "kern_util.h"
#include "os.h" #include "os.h"
#include "xterm.h" #include "xterm.h"
...@@ -19,17 +22,18 @@ struct xterm_wait { ...@@ -19,17 +22,18 @@ struct xterm_wait {
int new_fd; int new_fd;
}; };
static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
{ {
struct xterm_wait *xterm = data; struct xterm_wait *xterm = data;
int fd; int fd;
fd = os_rcv_fd(xterm->fd, &xterm->pid); fd = os_rcv_fd(xterm->fd, &xterm->pid);
if(fd == -EAGAIN) if(fd == -EAGAIN)
return; return(IRQ_NONE);
xterm->new_fd = fd; xterm->new_fd = fd;
up(&xterm->sem); up(&xterm->sem);
return(IRQ_HANDLED);
} }
int xterm_fd(int socket, int *pid_out) int xterm_fd(int socket, int *pid_out)
...@@ -54,7 +58,8 @@ int xterm_fd(int socket, int *pid_out) ...@@ -54,7 +58,8 @@ int xterm_fd(int socket, int *pid_out)
if(err){ if(err){
printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
"err = %d\n", err); "err = %d\n", err);
return(err); ret = err;
goto out;
} }
down(&data->sem); down(&data->sem);
...@@ -62,6 +67,7 @@ int xterm_fd(int socket, int *pid_out) ...@@ -62,6 +67,7 @@ int xterm_fd(int socket, int *pid_out)
ret = data->new_fd; ret = data->new_fd;
*pid_out = data->pid; *pid_out = data->pid;
out:
kfree(data); kfree(data);
return(ret); return(ret);
......
#include <asm-generic/vmlinux.lds.h>
OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_FORMAT(ELF_FORMAT)
OUTPUT_ARCH(ELF_ARCH) OUTPUT_ARCH(ELF_ARCH)
ENTRY(_start) ENTRY(_start)
...@@ -10,12 +12,15 @@ SECTIONS ...@@ -10,12 +12,15 @@ SECTIONS
{ {
. = START + SIZEOF_HEADERS; . = START + SIZEOF_HEADERS;
.interp : { *(.interp) } .interp : { *(.interp) }
. = ALIGN(4096);
__binary_start = .; __binary_start = .;
. = ALIGN(4096); /* Init code and data */ . = ALIGN(4096); /* Init code and data */
_stext = .; _stext = .;
__init_begin = .; __init_begin = .;
.text.init : { *(.text.init) } .init.text : {
_sinittext = .;
*(.init.text)
_einittext = .;
}
. = ALIGN(4096); . = ALIGN(4096);
...@@ -55,7 +60,9 @@ SECTIONS ...@@ -55,7 +60,9 @@ SECTIONS
} =0x90909090 } =0x90909090
.plt : { *(.plt) } .plt : { *(.plt) }
.text : { .text : {
*(.text .stub .text.* .gnu.linkonce.t.*) *(.text)
SCHED_TEXT
*(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */ /* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning) *(.gnu.warning)
} =0x90909090 } =0x90909090
...@@ -67,7 +74,7 @@ SECTIONS ...@@ -67,7 +74,7 @@ SECTIONS
#include "asm/common.lds.S" #include "asm/common.lds.S"
.data.init : { *(.data.init) } init.data : { *(.init.data) }
/* Ensure the __preinit_array_start label is properly aligned. We /* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but could instead move the label definition inside the section, but
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -11,6 +11,8 @@ extern int signal_stack_size; ...@@ -11,6 +11,8 @@ extern int signal_stack_size;
extern int change_sig(int signal, int on); extern int change_sig(int signal, int on);
extern void set_sigstack(void *stack, int size); extern void set_sigstack(void *stack, int size);
extern void set_handler(int sig, void (*handler)(int), int flags, ...); extern void set_handler(int sig, void (*handler)(int), int flags, ...);
extern int set_signals(int enable);
extern int get_signals(void);
#endif #endif
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment