Remove libuvt
uvt is not used inside of kmscon. Moved into a separate library if some-one is interested. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
parent
761434ecac
commit
9f2f11d2a5
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,7 +19,6 @@ configure
|
||||
*.tar.xz
|
||||
libtool
|
||||
libeloop.pc
|
||||
libuvt.pc
|
||||
libuterm.pc
|
||||
m4/
|
||||
stamp-*
|
||||
|
39
Makefile.am
39
Makefile.am
@ -11,10 +11,6 @@ LIBELOOP_CURRENT = 1
|
||||
LIBELOOP_REVISION = 0
|
||||
LIBELOOP_AGE = 0
|
||||
|
||||
LIBUVT_CURRENT = 1
|
||||
LIBUVT_REVISION = 0
|
||||
LIBUVT_AGE = 0
|
||||
|
||||
LIBUTERM_CURRENT = 1
|
||||
LIBUTERM_REVISION = 0
|
||||
LIBUTERM_AGE = 0
|
||||
@ -40,10 +36,8 @@ EXTRA_DIST = \
|
||||
docs/kmscon.service \
|
||||
docs/kmsconvt@.service \
|
||||
docs/pc/libeloop.pc.in \
|
||||
docs/pc/libuvt.pc.in \
|
||||
docs/pc/libuterm.pc.in \
|
||||
docs/sym/libeloop.sym \
|
||||
docs/sym/libuvt.sym \
|
||||
docs/sym/libuterm.sym
|
||||
CLEANFILES =
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
@ -236,39 +230,6 @@ libeloop_la_CPPFLAGS += $(DBUS_CFLAGS)
|
||||
libeloop_la_LIBADD += $(DBUS_LIBS)
|
||||
endif
|
||||
|
||||
#
|
||||
# libuvt
|
||||
# Implementation of Virtual Terminals in user-space with the help of CUSE/FUSE
|
||||
# so we can provide character-device drivers in user-space. Aims to be 100%
|
||||
# compatible but also provides many other use-cases.
|
||||
#
|
||||
|
||||
if BUILD_ENABLE_UVT
|
||||
lib_LTLIBRARIES += libuvt.la
|
||||
include_HEADERS += src/uvt.h
|
||||
pkgconfig_DATA += docs/pc/libuvt.pc
|
||||
endif
|
||||
|
||||
libuvt_la_SOURCES = \
|
||||
src/uvt.h \
|
||||
src/uvt_internal.h \
|
||||
src/uvt_ctx.c \
|
||||
src/uvt_cdev.c \
|
||||
src/uvt_client.c \
|
||||
src/uvt_tty_null.c
|
||||
libuvt_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(FUSE_CFLAGS) \
|
||||
-DFUSE_USE_VERSION=29
|
||||
libuvt_la_LIBADD = \
|
||||
$(FUSE_LIBS) \
|
||||
libshl.la
|
||||
EXTRA_libuvt_la_DEPENDENCIES = ${top_srcdir}/docs/sym/libuvt.sym
|
||||
libuvt_la_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-version-info $(LIBUVT_CURRENT):$(LIBUVT_REVISION):$(LIBUVT_AGE) \
|
||||
-Wl,--version-script="$(top_srcdir)/docs/sym/libuvt.sym"
|
||||
|
||||
#
|
||||
# libuterm
|
||||
# The uterm library provides helpers to create terminals in user-space. They
|
||||
|
1
README
1
README
@ -94,7 +94,6 @@ Released tarballs can be found at:
|
||||
--enable-kmscon: Build kmscon application [default: on]
|
||||
--enable-eloop: Build eloop event loop library [default: off]
|
||||
--enable-uterm: Build uterm library [default: off]
|
||||
--enable-uvt: Build UVT library [default: off]
|
||||
|
||||
== Running ==
|
||||
|
||||
|
50
configure.ac
50
configure.ac
@ -100,11 +100,6 @@ PKG_CHECK_MODULES([PANGO], [pango pangoft2],
|
||||
AC_SUBST(PANGO_CFLAGS)
|
||||
AC_SUBST(PANGO_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES([FUSE], [fuse >= 2.9.0],
|
||||
[have_fuse=yes], [have_fuse=no])
|
||||
AC_SUBST(FUSE_CFLAGS)
|
||||
AC_SUBST(FUSE_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES([CAIRO], [cairo],
|
||||
[have_cairo=yes], [have_cairo=no])
|
||||
AC_SUBST(CAIRO_CFLAGS)
|
||||
@ -149,18 +144,6 @@ elif test "x$enable_eloop" = "x" ; then
|
||||
fi
|
||||
AC_MSG_RESULT([$enable_eloop])
|
||||
|
||||
# UVT
|
||||
AC_MSG_CHECKING([whether user wants UVT])
|
||||
AC_ARG_ENABLE([uvt],
|
||||
[AS_HELP_STRING([--enable-uvt],
|
||||
[build uvt library])])
|
||||
if test "x$enable_all" = "xyes" ; then
|
||||
enable_uvt="yes"
|
||||
elif test "x$enable_uvt" = "x" ; then
|
||||
enable_uvt="no (default)"
|
||||
fi
|
||||
AC_MSG_RESULT([$enable_uvt])
|
||||
|
||||
# uterm
|
||||
AC_MSG_CHECKING([whether user wants uterm])
|
||||
AC_ARG_ENABLE([uterm],
|
||||
@ -448,25 +431,6 @@ else
|
||||
eloop_missing="enable-eloop"
|
||||
fi
|
||||
|
||||
# UVT
|
||||
uvt_avail=no
|
||||
uvt_missing=""
|
||||
if test ! "x$enable_uvt" = "xno" ; then
|
||||
uvt_avail=yes
|
||||
if test "x$have_fuse" = "xno" ; then
|
||||
uvt_avail=no
|
||||
uvt_missing="fuse"
|
||||
fi
|
||||
|
||||
if test "x$uvt_avail" = "xno" ; then
|
||||
if test "x$enable_uvt" = "xyes" ; then
|
||||
AC_ERROR([missing for UVT: $uvt_missing])
|
||||
fi
|
||||
fi
|
||||
else
|
||||
uvt_missing="enable-uvt"
|
||||
fi
|
||||
|
||||
# video fbdev
|
||||
video_fbdev_avail=no
|
||||
video_fbdev_missing=""
|
||||
@ -855,14 +819,6 @@ if test "x$video_fbdev_avail" = "xyes" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# UVT
|
||||
uvt_enabled=no
|
||||
if test "x$uvt_avail" = "xyes" ; then
|
||||
if test "x${enable_uvt% *}" = "xyes" ; then
|
||||
uvt_enabled=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
# eloop
|
||||
eloop_enabled=no
|
||||
if test "x$eloop_avail" = "xyes" ; then
|
||||
@ -925,10 +881,6 @@ AM_CONDITIONAL([BUILD_ENABLE_ELOOP_DBUS],
|
||||
AM_CONDITIONAL([BUILD_ENABLE_ELOOP],
|
||||
[test "x$eloop_enabled" = "xyes"])
|
||||
|
||||
# UVT
|
||||
AM_CONDITIONAL([BUILD_ENABLE_UVT],
|
||||
[test "x$uvt_enabled" = "xyes"])
|
||||
|
||||
# video fbdev
|
||||
if test "x$video_fbdev_enabled" = "xyes" ; then
|
||||
AC_DEFINE([BUILD_ENABLE_VIDEO_FBDEV], [1],
|
||||
@ -1117,7 +1069,6 @@ fi
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
docs/pc/libeloop.pc
|
||||
docs/pc/libuvt.pc
|
||||
docs/pc/libuterm.pc])
|
||||
AC_OUTPUT
|
||||
|
||||
@ -1137,7 +1088,6 @@ AC_MSG_NOTICE([Build configuration:
|
||||
Applications and Libraries:
|
||||
kmscon: $kmscon_enabled ($kmscon_avail: $kmscon_missing)
|
||||
uterm: $uterm_enabled ($uterm_avail: $uterm_missing)
|
||||
uvt: $uvt_enabled ($uvt_avail: $uvt_missing)
|
||||
eloop: $eloop_enabled ($eloop_avail: $eloop_missing)
|
||||
|
||||
Miscellaneous Options:
|
||||
|
@ -1,11 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: uvt
|
||||
Description: User-space Virtual Terminal Implementation
|
||||
URL: @PACKAGE_URL@
|
||||
Version: @PACKAGE_VERSION@
|
||||
Libs: -L${libdir} -luvt
|
||||
Cflags: -I${includedir}
|
@ -1,50 +0,0 @@
|
||||
/***
|
||||
* UVT - Userspace Virtual Terminals
|
||||
*
|
||||
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
***/
|
||||
|
||||
LIBUVT_1 {
|
||||
global:
|
||||
uvt_ctx_new;
|
||||
uvt_ctx_ref;
|
||||
uvt_ctx_unref;
|
||||
uvt_ctx_get_fd;
|
||||
uvt_ctx_dispatch;
|
||||
uvt_ctx_get_major;
|
||||
uvt_ctx_new_minor;
|
||||
uvt_ctx_free_minor;
|
||||
|
||||
uvt_cdev_new;
|
||||
uvt_cdev_ref;
|
||||
uvt_cdev_unref;
|
||||
uvt_cdev_register_cb;
|
||||
uvt_cdev_unregister_cb;
|
||||
|
||||
uvt_client_ref;
|
||||
uvt_client_unref;
|
||||
uvt_client_set_vt;
|
||||
uvt_client_kill;
|
||||
uvt_client_is_dead;
|
||||
local:
|
||||
*;
|
||||
};
|
274
src/uvt.h
274
src/uvt.h
@ -1,274 +0,0 @@
|
||||
/*
|
||||
* UVT - Userspace Virtual Terminals
|
||||
*
|
||||
* Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Userspace Virtual Terminals
|
||||
* Virtual terminals were historically implemented in the kernel via a
|
||||
* character-device. This layer provides a user-space implementation via
|
||||
* CUSE/FUSE that can be used to provide the same API from user-space.
|
||||
*/
|
||||
|
||||
#ifndef UVT_H
|
||||
#define UVT_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/vt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <termio.h>
|
||||
#include <termios.h>
|
||||
|
||||
/* UVT types */
|
||||
|
||||
struct uvt_client;
|
||||
struct uvt_cdev;
|
||||
struct uvt_ctx;
|
||||
|
||||
/* TTYs */
|
||||
|
||||
enum uvt_tty_event_type {
|
||||
UVT_TTY_HUP = 0x01,
|
||||
UVT_TTY_READ = 0x02,
|
||||
UVT_TTY_WRITE = 0x04,
|
||||
};
|
||||
|
||||
struct uvt_tty_event {
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
typedef void (*uvt_tty_cb) (void *tty, struct uvt_tty_event *ev, void *data);
|
||||
|
||||
struct uvt_tty_ops {
|
||||
void (*ref) (void *data);
|
||||
void (*unref) (void *data);
|
||||
int (*register_cb) (void *data, uvt_tty_cb cb, void *cb_data);
|
||||
void (*unregister_cb) (void *data, uvt_tty_cb cb, void *cb_data);
|
||||
|
||||
int (*read) (void *data, uint8_t *mem, size_t len);
|
||||
int (*write) (void *data, const uint8_t *mem, size_t len);
|
||||
unsigned int (*poll) (void *data);
|
||||
};
|
||||
|
||||
/* virtual terminals */
|
||||
|
||||
enum uvt_vt_event_type {
|
||||
UVT_VT_HUP = 0x01,
|
||||
UVT_VT_TTY = 0x02,
|
||||
};
|
||||
|
||||
struct uvt_vt_event {
|
||||
unsigned int type;
|
||||
|
||||
union {
|
||||
struct uvt_tty_event tty;
|
||||
};
|
||||
};
|
||||
|
||||
typedef void (*uvt_vt_cb) (void *vt, struct uvt_vt_event *ev, void *data);
|
||||
|
||||
struct uvt_vt_ops {
|
||||
void (*ref) (void *data);
|
||||
void (*unref) (void *data);
|
||||
int (*register_cb) (void *data, uvt_vt_cb cb, void *cb_data);
|
||||
void (*unregister_cb) (void *data, uvt_vt_cb cb, void *cb_data);
|
||||
|
||||
int (*read) (void *data, uint8_t *mem, size_t len);
|
||||
int (*write) (void *data, const uint8_t *mem, size_t len);
|
||||
unsigned int (*poll) (void *data);
|
||||
|
||||
/* TTY ioctls */
|
||||
int (*ioctl_TCFLSH) (void *data, unsigned long arg);
|
||||
|
||||
/* VT ioctls */
|
||||
int (*ioctl_VT_ACTIVATE) (void *data, unsigned long arg);
|
||||
int (*ioctl_VT_WAITACTIVE) (void *data, unsigned long arg);
|
||||
int (*ioctl_VT_GETSTATE) (void *data, struct vt_stat *arg);
|
||||
int (*ioctl_VT_OPENQRY) (void *data, unsigned int *arg);
|
||||
int (*ioctl_VT_GETMODE) (void *data, struct vt_mode *arg);
|
||||
int (*ioctl_VT_SETMODE) (void *data, const struct vt_mode *arg,
|
||||
pid_t pid);
|
||||
int (*ioctl_VT_RELDISP) (void *data, unsigned long arg);
|
||||
int (*ioctl_KDGETMODE) (void *data, unsigned int *arg);
|
||||
int (*ioctl_KDSETMODE) (void *data, unsigned int arg);
|
||||
int (*ioctl_KDGKBMODE) (void *data, unsigned int *arg);
|
||||
int (*ioctl_KDSKBMODE) (void *data, unsigned int arg);
|
||||
|
||||
/*
|
||||
Complete list of all ioctls that the kernel supports. The internal handler
|
||||
returns -EOPNOTSUPP for all of them as they haven't been implemented, yet.
|
||||
We need to check if they are actually required or whether it's not worth the
|
||||
effort.
|
||||
Please implement them only if you know a client that requires them. Also
|
||||
consider implementing them as a no-op if the client doesn't depend on the
|
||||
call to actually do something. We want to keep the actual callbacks at a
|
||||
minimum.
|
||||
|
||||
TTY ioctls
|
||||
|
||||
int (*ioctl_TIOCPKT) (void *data, ...);
|
||||
int (*ioctl_TCXONC) (void *data, ...);
|
||||
int (*ioctl_TCGETS) (void *data, struct termios *arg);
|
||||
int (*ioctl_TCSETS) (void *data, const struct termios *arg);
|
||||
int (*ioctl_TCSETSF) (void *data, const struct termios *arg);
|
||||
int (*ioctl_TCSETSW) (void *data, const struct termios *arg);
|
||||
int (*ioctl_TCGETA) (void *data, ...);
|
||||
int (*ioctl_TCSETA) (void *data, ...);
|
||||
int (*ioctl_TCSETAF) (void *data, ...);
|
||||
int (*ioctl_TCSETAW) (void *data, ...);
|
||||
int (*ioctl_TIOCGLCKTRMIOS) (void *data, ...);
|
||||
int (*ioctl_TIOCSLCKTRMIOS) (void *data, ...);
|
||||
int (*ioctl_TCGETX) (void *data, ...);
|
||||
int (*ioctl_TCSETX) (void *data, ...);
|
||||
int (*ioctl_TCSETXW) (void *data, ...);
|
||||
int (*ioctl_TCSETXF) (void *data, ...);
|
||||
int (*ioctl_TIOCGSOFTCAR) (void *data, ...);
|
||||
int (*ioctl_TIOCSSOFTCAR) (void *data, ...);
|
||||
|
||||
VT ioctls
|
||||
|
||||
int (*ioctl_TIOCLINUX) (void *data, ...);
|
||||
int (*ioctl_KIOCSOUND) (void *data, ...);
|
||||
int (*ioctl_KDMKTONE) (void *data, ...);
|
||||
int (*ioctl_KDGKBTYPE) (void *data, char *arg);
|
||||
int (*ioctl_KDADDIO) (void *data, unsigned long arg);
|
||||
int (*ioctl_KDDELIO) (void *data, unsigned long arg);
|
||||
int (*ioctl_KDENABIO) (void *data);
|
||||
int (*ioctl_KDDISABIO) (void *data);
|
||||
int (*ioctl_KDKBDREP) (void *data, struct kbd_repeat *arg);
|
||||
int (*ioctl_KDMAPDISP) (void *data);
|
||||
int (*ioctl_KDUNMAPDISP) (void *data);
|
||||
int (*ioctl_KDGKBMETA) (void *data, long *arg);
|
||||
int (*ioctl_KDSKBMETA) (void *data, long arg);
|
||||
int (*ioctl_KDGETKEYCODE) (void *data, ...);
|
||||
int (*ioctl_KDSETKEYCODE) (void *data, ...);
|
||||
int (*ioctl_KDGKBENT) (void *data, ...);
|
||||
int (*ioctl_KDSKBENT) (void *data, ...);
|
||||
int (*ioctl_KDGKBSENT) (void *data, ...);
|
||||
int (*ioctl_KDSKBSENT) (void *data, ...);
|
||||
int (*ioctl_KDGKBDIACR) (void *data, ...);
|
||||
int (*ioctl_KDSKBDIACR) (void *data, ...);
|
||||
int (*ioctl_KDGKBDIACRUC) (void *data, ...);
|
||||
int (*ioctl_KDSKBDIACRUC) (void *data, ...);
|
||||
int (*ioctl_KDGETLED) (void *data, char *arg);
|
||||
int (*ioctl_KDSETLED) (void *data, long arg);
|
||||
int (*ioctl_KDGKBLED) (void *data, char *arg);
|
||||
int (*ioctl_KDSKBLED) (void *data, long arg);
|
||||
int (*ioctl_KDSIGACCEPT) (void *data, ...);
|
||||
int (*ioctl_VT_SETACTIVATE) (void *data, ...);
|
||||
int (*ioctl_VT_DISALLOCATE) (void *data, ...);
|
||||
int (*ioctl_VT_RESIZE) (void *data, ...);
|
||||
int (*ioctl_VT_RESIZEX) (void *data, ...);
|
||||
int (*ioctl_GIO_FONT) (void *data, ...);
|
||||
int (*ioctl_PIO_FONT) (void *data, ...);
|
||||
int (*ioctl_GIO_CMAP) (void *data, ...);
|
||||
int (*ioctl_PIO_CMAP) (void *data, ...);
|
||||
int (*ioctl_GIO_FONTX) (void *data, ...);
|
||||
int (*ioctl_PIO_FONTX) (void *data, ...);
|
||||
int (*ioctl_PIO_FONTRESET) (void *data, ...);
|
||||
int (*ioctl_KDFONTOP) (void *data, ...);
|
||||
int (*ioctl_GIO_SCRNMAP) (void *data, ...);
|
||||
int (*ioctl_PIO_SCRNMAP) (void *data, ...);
|
||||
int (*ioctl_GIO_UNISCRNMAP) (void *data, ...);
|
||||
int (*ioctl_PIO_UNISCRNMAP) (void *data, ...);
|
||||
int (*ioctl_PIO_UNIMAPCLR) (void *data, ...);
|
||||
int (*ioctl_GIO_UNIMAP) (void *data, ...);
|
||||
int (*ioctl_PIO_UNIMAP) (void *data, ...);
|
||||
int (*ioctl_VT_LOCKSWITCH) (void *data);
|
||||
int (*ioctl_VT_UNLOCKSWITCH) (void *data);
|
||||
int (*ioctl_VT_GETHIFONTMASK) (void *data, ...);
|
||||
int (*ioctl_VT_WAITEVENT) (void *data, ...);
|
||||
*/
|
||||
};
|
||||
|
||||
/* client sessions */
|
||||
|
||||
void uvt_client_ref(struct uvt_client *client);
|
||||
void uvt_client_unref(struct uvt_client *client);
|
||||
|
||||
int uvt_client_set_vt(struct uvt_client *client, const struct uvt_vt_ops *vt,
|
||||
void *vt_data);
|
||||
void uvt_client_kill(struct uvt_client *client);
|
||||
bool uvt_client_is_dead(struct uvt_client *client);
|
||||
|
||||
/* character devices */
|
||||
|
||||
enum uvt_cdev_event_type {
|
||||
UVT_CDEV_HUP,
|
||||
UVT_CDEV_OPEN,
|
||||
};
|
||||
|
||||
struct uvt_cdev_event {
|
||||
unsigned int type;
|
||||
|
||||
union {
|
||||
struct uvt_client *client;
|
||||
};
|
||||
};
|
||||
|
||||
typedef void (*uvt_cdev_cb) (struct uvt_cdev *cdev,
|
||||
struct uvt_cdev_event *ev,
|
||||
void *data);
|
||||
|
||||
int uvt_cdev_new(struct uvt_cdev **out, struct uvt_ctx *ctx,
|
||||
const char *name, unsigned int major, unsigned int minor);
|
||||
void uvt_cdev_ref(struct uvt_cdev *cdev);
|
||||
void uvt_cdev_unref(struct uvt_cdev *cdev);
|
||||
|
||||
int uvt_cdev_register_cb(struct uvt_cdev *cdev, uvt_cdev_cb cb, void *data);
|
||||
void uvt_cdev_unregister_cb(struct uvt_cdev *cdev, uvt_cdev_cb cb, void *data);
|
||||
|
||||
/* contexts */
|
||||
|
||||
typedef void (*uvt_log_t) (void *data,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *subs,
|
||||
unsigned int sev,
|
||||
const char *format,
|
||||
va_list args);
|
||||
|
||||
int uvt_ctx_new(struct uvt_ctx **out, uvt_log_t log, void *log_data);
|
||||
void uvt_ctx_ref(struct uvt_ctx *ctx);
|
||||
void uvt_ctx_unref(struct uvt_ctx *ctx);
|
||||
|
||||
int uvt_ctx_get_fd(struct uvt_ctx *ctx);
|
||||
void uvt_ctx_dispatch(struct uvt_ctx *ctx);
|
||||
|
||||
unsigned int uvt_ctx_get_major(struct uvt_ctx *ctx);
|
||||
int uvt_ctx_new_minor(struct uvt_ctx *ctx, unsigned int *out);
|
||||
void uvt_ctx_free_minor(struct uvt_ctx *ctx, unsigned int minor);
|
||||
|
||||
/* pty tty implementation */
|
||||
|
||||
struct uvt_tty_null;
|
||||
extern const struct uvt_tty_ops uvt_tty_null_ops;
|
||||
|
||||
int uvt_tty_null_new(struct uvt_tty_null **out, struct uvt_ctx *ctx);
|
||||
void uvt_tty_null_ref(struct uvt_tty_null *tty);
|
||||
void uvt_tty_null_unref(struct uvt_tty_null *tty);
|
||||
|
||||
#endif /* UVT_H */
|
485
src/uvt_cdev.c
485
src/uvt_cdev.c
@ -1,485 +0,0 @@
|
||||
/*
|
||||
* UVT - Userspace Virtual Terminals
|
||||
*
|
||||
* Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Character Devices
|
||||
* This implements a VT character device entry point via the CUSE API. It does
|
||||
* not implement the VT API on top of the character-device (cdev) but only
|
||||
* provides the entry point. It is up to the user to bind open-files to VT and
|
||||
* client objects.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/major.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "shl_dlist.h"
|
||||
#include "shl_hook.h"
|
||||
#include "shl_llog.h"
|
||||
#include "uvt.h"
|
||||
#include "uvt_internal.h"
|
||||
|
||||
#include <fuse/fuse.h>
|
||||
#include <fuse/fuse_common.h>
|
||||
#include <fuse/fuse_lowlevel.h>
|
||||
#include <fuse/fuse_opt.h>
|
||||
#include <fuse/cuse_lowlevel.h>
|
||||
|
||||
#define LLOG_SUBSYSTEM "uvt_cdev"
|
||||
|
||||
/*
|
||||
* FUSE low-level ops
|
||||
* This implements all the file-system operations on the character-device. It
|
||||
* is important that we handle interrupts correctly (ENOENT) and never loose
|
||||
* any data. This is all single threaded as it is not performance critical at
|
||||
* all.
|
||||
* We simply dispatch each call to uvt_client as this implements all the
|
||||
* client-session related operations.
|
||||
*/
|
||||
|
||||
static void ll_open(fuse_req_t req, struct fuse_file_info *fi)
|
||||
{
|
||||
struct uvt_cdev *cdev = fuse_req_userdata(req);
|
||||
struct uvt_client *client;
|
||||
struct uvt_cdev_event ev;
|
||||
int ret;
|
||||
|
||||
ret = uvt_client_ll_open(&client, cdev, req, fi);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = UVT_CDEV_OPEN;
|
||||
ev.client = client;
|
||||
shl_hook_call(cdev->hook, cdev, &ev);
|
||||
}
|
||||
|
||||
static void ll_destroy(void *data) {
|
||||
struct uvt_cdev *cdev = data;
|
||||
struct uvt_client *client;
|
||||
|
||||
/* on unexpected shutdown this kills all open clients */
|
||||
while (!shl_dlist_empty(&cdev->clients)) {
|
||||
client = shl_dlist_entry(cdev->clients.next,
|
||||
struct uvt_client, list);
|
||||
uvt_client_kill(client);
|
||||
uvt_client_unref(client);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct cuse_lowlevel_ops ll_ops = {
|
||||
.init = NULL,
|
||||
.destroy = ll_destroy,
|
||||
.open = ll_open,
|
||||
.release = uvt_client_ll_release,
|
||||
.read = uvt_client_ll_read,
|
||||
.write = uvt_client_ll_write,
|
||||
.poll = uvt_client_ll_poll,
|
||||
.ioctl = uvt_client_ll_ioctl,
|
||||
.flush = NULL,
|
||||
.fsync = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* FUSE channel ops
|
||||
* The connection to the FUSE kernel module is done via a file-descriptor.
|
||||
* Writing to it is synchronous, so the commands that we write are
|
||||
* _immediately_ executed and return the result to us. Furthermore, write()
|
||||
* is always non-blocking and always succeeds so no reason to watch for
|
||||
* EAGAIN. Reading from the FD, on the other hand, may block if there is no
|
||||
* data available so we mark it as O_NONBLOCK. The kernel maintains
|
||||
* an event-queue that we read from. So there may be pending events that we
|
||||
* haven't read but which affect the calls that we write to the kernel. This
|
||||
* is important when handling interrupts.
|
||||
* chan_receive() and chan_send() handle I/O to the kernel module and are
|
||||
* hooked up into a fuse-channel.
|
||||
*/
|
||||
|
||||
static int chan_receive(struct fuse_chan **chp, char *buf, size_t size)
|
||||
{
|
||||
struct fuse_chan *ch = *chp;
|
||||
struct uvt_cdev *cdev = fuse_chan_data(ch);
|
||||
struct fuse_session *se = fuse_chan_session(ch);
|
||||
int fd = fuse_chan_fd(ch);
|
||||
ssize_t res;
|
||||
|
||||
if (!se || !cdev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
restart:
|
||||
if (fuse_session_exited(se))
|
||||
return 0;
|
||||
|
||||
res = read(fd, buf, size);
|
||||
if (!res) {
|
||||
/* EOF on cuse file */
|
||||
llog_error(cdev, "fuse channel shut down on cdev %p", cdev);
|
||||
fuse_session_exit(se);
|
||||
return 0;
|
||||
} else if (res < 0) {
|
||||
/* ENOENT is returned if the operation was interrupted, it's
|
||||
* safe to restart */
|
||||
if (errno == ENOENT)
|
||||
goto restart;
|
||||
|
||||
/* ENODEV is returned if the FS got unmounted. This shouldn't
|
||||
* occur for CUSE devices. Anyway, exit if this happens. */
|
||||
if (errno == ENODEV) {
|
||||
llog_error(cdev, "fuse channel unmounted on cdev %p",
|
||||
cdev);
|
||||
fuse_session_exit(se);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EINTR and EAGAIN are simply forwarded to the caller. */
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
return -errno;
|
||||
|
||||
cdev->error = -errno;
|
||||
llog_error(cdev, "fuse channel read error on cdev %p (%d): %m",
|
||||
cdev, errno);
|
||||
fuse_session_exit(se);
|
||||
return cdev->error;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int chan_send(struct fuse_chan *ch, const struct iovec iov[],
|
||||
size_t count)
|
||||
{
|
||||
struct uvt_cdev *cdev = fuse_chan_data(ch);
|
||||
struct fuse_session *se = fuse_chan_session(ch);
|
||||
int fd = fuse_chan_fd(ch);
|
||||
int ret;
|
||||
|
||||
if (!cdev || !se)
|
||||
return -EINVAL;
|
||||
if (!iov || !count)
|
||||
return 0;
|
||||
|
||||
ret = writev(fd, iov, count);
|
||||
if (ret < 0) {
|
||||
/* ENOENT is returned on interrupts */
|
||||
if (!fuse_session_exited(se) && errno != ENOENT) {
|
||||
cdev->error = -errno;
|
||||
llog_error(cdev, "cannot write to fuse-channel on cdev %p (%d): %m",
|
||||
cdev, errno);
|
||||
fuse_session_exit(se);
|
||||
}
|
||||
return cdev->error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fuse_chan_ops chan_ops = {
|
||||
.receive = chan_receive,
|
||||
.send = chan_send,
|
||||
.destroy = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Character Device
|
||||
* This creates the high-level character-device driver and registers a
|
||||
* fake-session that is used to control each character file.
|
||||
* channel_event() is a callback when I/O is possible on the FUSE FD and
|
||||
* performs all outstanding tasks.
|
||||
* On error, the fake-session is unregistered and deleted. This also stops all
|
||||
* client sessions, obviously.
|
||||
*/
|
||||
|
||||
static void uvt_cdev_hup(struct uvt_cdev *cdev, int error)
|
||||
{
|
||||
struct uvt_cdev_event ev;
|
||||
|
||||
ev_eloop_rm_fd(cdev->efd);
|
||||
cdev->efd = NULL;
|
||||
cdev->error = error;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = UVT_CDEV_HUP;
|
||||
|
||||
shl_hook_call(cdev->hook, cdev, &ev);
|
||||
}
|
||||
|
||||
static void channel_event(struct ev_fd *fd, int mask, void *data)
|
||||
{
|
||||
struct uvt_cdev *cdev = data;
|
||||
int ret;
|
||||
struct fuse_buf buf;
|
||||
struct fuse_chan *ch;
|
||||
struct shl_dlist *iter;
|
||||
struct uvt_client *client;
|
||||
|
||||
if (!(mask & EV_READABLE)) {
|
||||
if (mask & (EV_HUP | EV_ERR)) {
|
||||
llog_error(cdev, "HUP/ERR on fuse channel on cdev %p",
|
||||
cdev);
|
||||
uvt_cdev_hup(cdev, -EPIPE);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.mem = cdev->buf;
|
||||
buf.size = cdev->bufsize;
|
||||
ch = cdev->channel;
|
||||
ret = fuse_session_receive_buf(cdev->session, &buf, &ch);
|
||||
if (ret == -EINTR || ret == -EAGAIN) {
|
||||
return;
|
||||
} else if (ret < 0) {
|
||||
llog_error(cdev, "fuse channel read error on cdev %p: %d",
|
||||
cdev, ret);
|
||||
uvt_cdev_hup(cdev, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
fuse_session_process_buf(cdev->session, &buf, ch);
|
||||
if (fuse_session_exited(cdev->session)) {
|
||||
llog_error(cdev, "fuse session exited on cdev %p", cdev);
|
||||
uvt_cdev_hup(cdev, cdev->error ? : -EFAULT);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Readers can get interrupted asynchronously. Due to heavy locking
|
||||
* inside of FUSE, we cannot release them right away. So cleanup all
|
||||
* killed readers after we processed all buffers. */
|
||||
shl_dlist_for_each(iter, &cdev->clients) {
|
||||
client = shl_dlist_entry(iter, struct uvt_client, list);
|
||||
uvt_client_cleanup(client);
|
||||
}
|
||||
}
|
||||
|
||||
static int uvt_cdev_init(struct uvt_cdev *cdev, const char *name,
|
||||
unsigned int major, unsigned int minor)
|
||||
{
|
||||
const char *dev_info_argv[1];
|
||||
struct cuse_info ci;
|
||||
size_t bufsize;
|
||||
char *nparam;
|
||||
int ret;
|
||||
|
||||
/* TODO: libfuse makes sure that fd 0, 1 and 2 are available as
|
||||
* standard streams, otherwise they fail. This is awkward and we
|
||||
* should check whether this is really needed and _why_?
|
||||
* If it is needed, fix upstream to stop that crazy! */
|
||||
|
||||
if (!major)
|
||||
major = TTY_MAJOR;
|
||||
|
||||
if (!major || major > 255) {
|
||||
llog_error(cdev, "invalid major %u on cdev %p",
|
||||
major, cdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!minor) {
|
||||
llog_error(cdev, "invalid minor %u on cdev %p",
|
||||
minor, cdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!name || !*name) {
|
||||
llog_error(cdev, "empty name on cdev %p",
|
||||
cdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
llog_info(cdev, "creating device /dev/%s %u:%u on cdev %p",
|
||||
name, major, minor, cdev);
|
||||
|
||||
ret = asprintf(&nparam, "DEVNAME=%s", name);
|
||||
if (ret <= 0)
|
||||
return llog_ENOMEM(cdev);
|
||||
|
||||
dev_info_argv[0] = nparam;
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
ci.dev_major = major;
|
||||
ci.dev_minor = minor;
|
||||
ci.dev_info_argc = 1;
|
||||
ci.dev_info_argv = dev_info_argv;
|
||||
ci.flags = CUSE_UNRESTRICTED_IOCTL;
|
||||
|
||||
cdev->session = cuse_lowlevel_new(NULL, &ci, &ll_ops, cdev);
|
||||
free(nparam);
|
||||
|
||||
if (!cdev->session) {
|
||||
llog_error(cdev, "cannot create fuse-ll session on cdev %p",
|
||||
cdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cdev->fd = open(cdev->ctx->cuse_file, O_RDWR | O_CLOEXEC | O_NONBLOCK);
|
||||
if (cdev->fd < 0) {
|
||||
llog_error(cdev, "cannot open cuse-file %s on cdev %p (%d): %m",
|
||||
cdev->ctx->cuse_file, cdev, errno);
|
||||
ret = -EFAULT;
|
||||
goto err_session;
|
||||
}
|
||||
|
||||
bufsize = getpagesize() + 0x1000;
|
||||
if (bufsize < 0x21000)
|
||||
bufsize = 0x21000;
|
||||
|
||||
cdev->bufsize = bufsize;
|
||||
cdev->buf = malloc(bufsize);
|
||||
if (!cdev->buf) {
|
||||
ret = llog_ENOMEM(cdev);
|
||||
goto err_fd;
|
||||
}
|
||||
|
||||
/* Argh! libfuse does not use "const" for the "chan_ops" pointer so we
|
||||
* actually have to cast it. Their implementation does not write into it
|
||||
* so we can safely use a constant storage for it.
|
||||
* TODO: Fix libfuse upstream! */
|
||||
cdev->channel = fuse_chan_new((void*)&chan_ops, cdev->fd, bufsize,
|
||||
cdev);
|
||||
if (!cdev->channel) {
|
||||
llog_error(cdev, "cannot allocate fuse-channel on cdev %p",
|
||||
cdev);
|
||||
ret = -ENOMEM;
|
||||
goto err_buf;
|
||||
}
|
||||
|
||||
ret = ev_eloop_new_fd(cdev->ctx->eloop, &cdev->efd, cdev->fd,
|
||||
EV_READABLE, channel_event, cdev);
|
||||
if (ret)
|
||||
goto err_chan;
|
||||
|
||||
fuse_session_add_chan(cdev->session, cdev->channel);
|
||||
return 0;
|
||||
|
||||
err_chan:
|
||||
fuse_chan_destroy(cdev->channel);
|
||||
err_buf:
|
||||
free(cdev->buf);
|
||||
err_fd:
|
||||
close(cdev->fd);
|
||||
err_session:
|
||||
fuse_session_destroy(cdev->session);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void uvt_cdev_destroy(struct uvt_cdev *cdev)
|
||||
{
|
||||
if (cdev->error)
|
||||
llog_warning(cdev, "cdev %p failed with error %d",
|
||||
cdev, cdev->error);
|
||||
|
||||
fuse_session_destroy(cdev->session);
|
||||
ev_eloop_rm_fd(cdev->efd);
|
||||
free(cdev->buf);
|
||||
close(cdev->fd);
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
int uvt_cdev_new(struct uvt_cdev **out, struct uvt_ctx *ctx,
|
||||
const char *name, unsigned int major, unsigned int minor)
|
||||
{
|
||||
struct uvt_cdev *cdev;
|
||||
int ret;
|
||||
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
if (!out)
|
||||
return llog_EINVAL(ctx);
|
||||
|
||||
cdev = malloc(sizeof(*cdev));
|
||||
if (!cdev)
|
||||
return llog_ENOMEM(ctx);
|
||||
memset(cdev, 0, sizeof(*cdev));
|
||||
cdev->ref = 1;
|
||||
cdev->ctx = ctx;
|
||||
cdev->llog = ctx->llog;
|
||||
cdev->llog_data = ctx->llog_data;
|
||||
shl_dlist_init(&cdev->clients);
|
||||
|
||||
llog_debug(cdev, "new cdev %p on ctx %p", cdev, cdev->ctx);
|
||||
|
||||
ret = shl_hook_new(&cdev->hook);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
ret = uvt_cdev_init(cdev, name, major, minor);
|
||||
if (ret)
|
||||
goto err_hook;
|
||||
|
||||
uvt_ctx_ref(cdev->ctx);
|
||||
*out = cdev;
|
||||
return 0;
|
||||
|
||||
err_hook:
|
||||
shl_hook_free(cdev->hook);
|
||||
err_free:
|
||||
free(cdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_cdev_ref(struct uvt_cdev *cdev)
|
||||
{
|
||||
if (!cdev || !cdev->ref)
|
||||
return;
|
||||
|
||||
++cdev->ref;
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_cdev_unref(struct uvt_cdev *cdev)
|
||||
{
|
||||
if (!cdev || !cdev->ref || --cdev->ref)
|
||||
return;
|
||||
|
||||
llog_debug(cdev, "free cdev %p", cdev);
|
||||
|
||||
uvt_cdev_destroy(cdev);
|
||||
shl_hook_free(cdev->hook);
|
||||
uvt_ctx_unref(cdev->ctx);
|
||||
free(cdev);
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
int uvt_cdev_register_cb(struct uvt_cdev *cdev, uvt_cdev_cb cb, void *data)
|
||||
{
|
||||
if (!cdev)
|
||||
return -EINVAL;
|
||||
|
||||
return shl_hook_add_cast(cdev->hook, cb, data, false);
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_cdev_unregister_cb(struct uvt_cdev *cdev, uvt_cdev_cb cb, void *data)
|
||||
{
|
||||
if (!cdev)
|
||||
return;
|
||||
|
||||
shl_hook_rm_cast(cdev->hook, cb, data);
|
||||
}
|
1120
src/uvt_client.c
1120
src/uvt_client.c
File diff suppressed because it is too large
Load Diff
168
src/uvt_ctx.c
168
src/uvt_ctx.c
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* UVT - Userspace Virtual Terminals
|
||||
*
|
||||
* Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* UVT Contexts
|
||||
* A UVT context is used to provide basic infrastructure for all other UVT
|
||||
* objects. It allows easy integration of multiple UVT objects into a single
|
||||
* application.
|
||||
*/
|
||||
|
||||
#include <eloop.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/major.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "shl_array.h"
|
||||
#include "shl_flagset.h"
|
||||
#include "shl_llog.h"
|
||||
#include "shl_misc.h"
|
||||
#include "uvt.h"
|
||||
#include "uvt_internal.h"
|
||||
|
||||
#define LLOG_SUBSYSTEM "uvt_ctx"
|
||||
|
||||
SHL_EXPORT
|
||||
int uvt_ctx_new(struct uvt_ctx **out, uvt_log_t log, void *log_data)
|
||||
{
|
||||
struct uvt_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
if (!out)
|
||||
return llog_dEINVAL(log, log_data);
|
||||
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
if (!ctx)
|
||||
return llog_dENOMEM(log, log_data);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->ref = 1;
|
||||
ctx->llog = log;
|
||||
ctx->llog_data = log_data;
|
||||
|
||||
/* Default major/minor uses the TTY_MAJOR number with an offset of 2^15
|
||||
* to avoid ID-clashes with any in-kernel TTY driver. As kernel drivers
|
||||
* use static IDs only, a lower number would be fine, too, but lets be
|
||||
* safe and just use high numbers. */
|
||||
ctx->major = TTY_MAJOR;
|
||||
ctx->minor_offset = 16384;
|
||||
|
||||
llog_debug(ctx, "new ctx %p", ctx);
|
||||
|
||||
ret = ev_eloop_new(&ctx->eloop, ctx->llog, ctx->llog_data);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
ctx->cuse_file = strdup("/dev/cuse");
|
||||
if (!ctx->cuse_file) {
|
||||
ret = llog_ENOMEM(ctx);
|
||||
goto err_eloop;
|
||||
}
|
||||
|
||||
ret = shl_flagset_new(&ctx->minors);
|
||||
if (ret)
|
||||
goto err_file;
|
||||
|
||||
*out = ctx;
|
||||
return 0;
|
||||
|
||||
err_file:
|
||||
free(ctx->cuse_file);
|
||||
err_eloop:
|
||||
ev_eloop_unref(ctx->eloop);
|
||||
err_free:
|
||||
free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_ctx_ref(struct uvt_ctx *ctx)
|
||||
{
|
||||
if (!ctx || !ctx->ref)
|
||||
return;
|
||||
|
||||
++ctx->ref;
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_ctx_unref(struct uvt_ctx *ctx)
|
||||
{
|
||||
if (!ctx || !ctx->ref || --ctx->ref)
|
||||
return;
|
||||
|
||||
llog_debug(ctx, "free ctx %p", ctx);
|
||||
|
||||
shl_flagset_free(ctx->minors);
|
||||
free(ctx->cuse_file);
|
||||
ev_eloop_unref(ctx->eloop);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
int uvt_ctx_get_fd(struct uvt_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return -1;
|
||||
|
||||
return ev_eloop_get_fd(ctx->eloop);
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_ctx_dispatch(struct uvt_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
ev_eloop_dispatch(ctx->eloop, 0);
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
unsigned int uvt_ctx_get_major(struct uvt_ctx *ctx)
|
||||
{
|
||||
return ctx->major;
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
int uvt_ctx_new_minor(struct uvt_ctx *ctx, unsigned int *out)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = shl_flagset_alloc(ctx->minors, out);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*out += ctx->minor_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHL_EXPORT
|
||||
void uvt_ctx_free_minor(struct uvt_ctx *ctx, unsigned int minor)
|
||||
{
|
||||
if (!ctx || minor < ctx->minor_offset)
|
||||
return;
|
||||
|
||||
shl_flagset_unset(ctx->minors, minor - ctx->minor_offset);
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* UVT - Userspace Virtual Terminals
|
||||
*
|
||||
* Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Userspace Virtual Terminals Internals
|
||||
* Internal header of the UVT implementation.
|
||||
*/
|
||||
|
||||
#ifndef UVT_INTERNAL_H
|
||||
#define UVT_INTERNAL_H
|
||||
|
||||
#include <eloop.h>
|
||||
#include <stdlib.h>
|
||||
#include <uvt.h>
|
||||
#include "shl_array.h"
|
||||
#include "shl_dlist.h"
|
||||
#include "shl_hook.h"
|
||||
#include "shl_llog.h"
|
||||
|
||||
#include <fuse/fuse.h>
|
||||
#include <fuse/fuse_common.h>
|
||||
#include <fuse/fuse_lowlevel.h>
|
||||
#include <fuse/fuse_opt.h>
|
||||
#include <fuse/cuse_lowlevel.h>
|
||||
|
||||
/* contexts */
|
||||
|
||||
struct uvt_ctx {
|
||||
unsigned long ref;
|
||||
llog_submit_t llog;
|
||||
void *llog_data;
|
||||
struct ev_eloop *eloop;
|
||||
|
||||
char *cuse_file;
|
||||
unsigned int major;
|
||||
unsigned int minor_offset;
|
||||
struct shl_array *minors;
|
||||
};
|
||||
|
||||
/* character devices */
|
||||
|
||||
struct uvt_cdev {
|
||||
unsigned long ref;
|
||||
struct uvt_ctx *ctx;
|
||||
llog_submit_t llog;
|
||||
void *llog_data;
|
||||
|
||||
int error;
|
||||
struct shl_hook *hook;
|
||||
|
||||
struct fuse_session *session;
|
||||
int fd;
|
||||
struct fuse_chan *channel;
|
||||
struct ev_fd *efd;
|
||||
|
||||
size_t bufsize;
|
||||
char *buf;
|
||||
|
||||
struct shl_dlist clients;
|
||||
};
|
||||
|
||||
/* client sessions */
|
||||
|
||||
struct uvt_client {
|
||||
unsigned long ref;
|
||||
struct shl_dlist list;
|
||||
struct uvt_cdev *cdev;
|
||||
llog_submit_t llog;
|
||||
void *llog_data;
|
||||
|
||||
struct fuse_pollhandle *ph;
|
||||
struct shl_dlist waiters;
|
||||
|
||||
const struct uvt_vt_ops *vt;
|
||||
void *vt_data;
|
||||
bool vt_locked;
|
||||
bool vt_in_unlock;
|
||||
unsigned int vt_retry;
|
||||
};
|
||||
|
||||
void uvt_client_cleanup(struct uvt_client *client);
|
||||
|
||||
int uvt_client_ll_open(struct uvt_client **out, struct uvt_cdev *cdev,
|
||||
fuse_req_t req, struct fuse_file_info *fi);
|
||||
void uvt_client_ll_release(fuse_req_t req, struct fuse_file_info *fi);
|
||||
void uvt_client_ll_read(fuse_req_t req, size_t size, off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
void uvt_client_ll_write(fuse_req_t req, const char *buf, size_t size,
|
||||
off_t off, struct fuse_file_info *fi);
|
||||
void uvt_client_ll_poll(fuse_req_t req, struct fuse_file_info *fi,
|
||||
struct fuse_pollhandle *ph);
|
||||
void uvt_client_ll_ioctl(fuse_req_t req, int cmd, void *arg,
|
||||
struct fuse_file_info *fi, unsigned int flags,
|
||||
const void *in_buf, size_t in_bufsz, size_t out_bufsz);
|
||||
|
||||
#endif /* UVT_INTERNAL_H */
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* UVT - Userspace Virtual Terminals
|
||||
*
|
||||
* Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Null TTY
|
||||
* This tty simply discards all incoming messages and never produces any
|
||||
* outgoing messages. Ioctls return static data or fail with some generic error
|
||||
* code if they would modify internal state that we cannot emulate easily.
|
||||
*/
|
||||
|
||||
#include <eloop.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "shl_llog.h"
|
||||
#include "uvt.h"
|
||||
#include "uvt_internal.h"
|
||||
|
||||
#define LLOG_SUBSYSTEM "uvt_tty_null"
|
||||
|
||||
struct uvt_tty_null {
|
||||
unsigned long ref;
|
||||
struct uvt_ctx *ctx;
|
||||
llog_submit_t llog;
|
||||
void *llog_data;
|
||||
};
|
||||
|
||||
static void tty_null_ref(void *data)
|
||||
{
|
||||
uvt_tty_null_ref(data);
|
||||
}
|
||||
|
||||
static void tty_null_unref(void *data)
|
||||
{
|
||||
uvt_tty_null_unref(data);
|
||||
}
|
||||
|
||||
static int tty_null_register_cb(void *data, uvt_tty_cb cb, void *cb_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tty_null_unregister_cb(void *data, uvt_tty_cb cb, void *cb_data)
|
||||
{
|
||||
}
|
||||
|
||||
static int tty_null_read(void *data, uint8_t *buf, size_t size)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int tty_null_write(void *data, const uint8_t *buf, size_t size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
static unsigned int tty_null_poll(void *data)
|
||||
{
|
||||
return UVT_TTY_WRITE;
|
||||
}
|
||||
|
||||
const struct uvt_tty_ops uvt_tty_null_ops = {
|
||||
.ref = tty_null_ref,
|
||||
.unref = tty_null_unref,
|
||||
.register_cb = tty_null_register_cb,
|
||||
.unregister_cb = tty_null_unregister_cb,
|
||||
|
||||
.read = tty_null_read,
|
||||
.write = tty_null_write,
|
||||
.poll = tty_null_poll,
|
||||
};
|
||||
|
||||
int uvt_tty_null_new(struct uvt_tty_null **out, struct uvt_ctx *ctx)
|
||||
{
|
||||
struct uvt_tty_null *tty;
|
||||
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
if (!out)
|
||||
return llog_EINVAL(ctx);
|
||||
|
||||
tty = malloc(sizeof(*tty));
|
||||
if (!tty)
|
||||
return llog_ENOMEM(ctx);
|
||||
memset(tty, 0, sizeof(*tty));
|
||||
tty->ref = 1;
|
||||
tty->ctx = ctx;
|
||||
tty->llog = tty->ctx->llog;
|
||||
tty->llog_data = tty->ctx->llog_data;
|
||||
|
||||
uvt_ctx_ref(tty->ctx);
|
||||
*out = tty;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uvt_tty_null_ref(struct uvt_tty_null *tty)
|
||||
{
|
||||
if (!tty || !tty->ref)
|
||||
return;
|
||||
|
||||
++tty->ref;
|
||||
}
|
||||
|
||||
void uvt_tty_null_unref(struct uvt_tty_null *tty)
|
||||
{
|
||||
if (!tty || !tty->ref || --tty->ref)
|
||||
return;
|
||||
|
||||
uvt_ctx_unref(tty->ctx);
|
||||
free(tty);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user