From 5ab78e8b939366aa096c28898bbf20ddcb3a61f4 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 20 Apr 2010 14:21:39 +0200 Subject: [PATCH 1/4] tty notifier --- drivers/char/Kconfig | 6 ++ drivers/char/tty_io.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/tty.h | 22 +++++++++ 3 files changed, 153 insertions(+), 0 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 3141dd3..9be342e 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1113,5 +1113,11 @@ config DEVPORT source "drivers/s390/char/Kconfig" +config TTY_NOTIFIER + bool "Terminal notifier" + depends on EXPERIMENTAL + default n + help + Interface to norify about terminals' data and state changes. endmenu diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6da962c..f0463d0 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -154,6 +154,112 @@ static void release_tty(struct tty_struct *tty, int idx); static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); +#ifdef CONFIG_TTY_NOTIFIER +static LIST_HEAD(tty_structs); /* linked list of tty structs */ +static ATOMIC_NOTIFIER_HEAD(tty_notifier_list); + +/** + * register_tty_notifier - register tty notifier + * + * Locking: none + */ + +int register_tty_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&tty_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(register_tty_notifier); + +/** + * unregister_tty_notifier - unregister tty notifier + * + * Locking: none + */ + +int unregister_tty_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&tty_notifier_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_tty_notifier); + + +/** + * notify_tty_open - notify about tty open + * + * Calls the tty notifier chain. + * + * Locking: none + */ + +static void notify_tty_create(struct tty_struct *tty) +{ + struct tty_notifier_param param = { + .tty = tty, + }; + + atomic_notifier_call_chain(&tty_notifier_list, TTY_NOTIFY_CREATE, ¶m); +} + +/** + * notify_tty_close - notify about tty close + * + * Calls the tty notifier chain. + * + * Locking: none + */ + +static void notify_tty_release(struct tty_struct *tty) +{ + struct tty_notifier_param param = { + .tty = tty, + }; + + atomic_notifier_call_chain(&tty_notifier_list, TTY_NOTIFY_RELEASE, ¶m); +} + +/** + * notify_tty_data - notify about tty data + * + * Calls the tty notifier chain. + * + * Locking: none + */ + +static void notify_tty_data(struct tty_struct *tty, unsigned char *buf, size_t size) +{ + struct tty_notifier_param param = { + .tty = tty, + .buf = buf, + .size = size + }; + + atomic_notifier_call_chain(&tty_notifier_list, TTY_NOTIFY_DATA, ¶m); +} + +/** + * tty_del - remove tty from the global list + * + * Locking: tty_mutex + */ + +static void tty_del(struct tty_struct *tty) +{ + + mutex_lock(&tty_mutex); + + /* It's the master who's on the list... */ + if (tty->driver->type == TTY_DRIVER_TYPE_PTY) + if (tty->driver->subtype == PTY_TYPE_SLAVE); + tty = tty->link; + + if (tty) + list_del(&tty->list); + + mutex_unlock(&tty_mutex); +} + +#endif + /** * alloc_tty_struct - allocate a tty object * @@ -981,6 +1087,11 @@ static inline ssize_t do_tty_write( ret = -EFAULT; if (copy_from_user(tty->write_buf, buf, size)) break; + +#ifdef CONFIG_TTY_NOTIFIER + notify_tty_data(tty, tty->write_buf, size); +#endif + ret = write(tty, file, tty->write_buf, size); if (ret <= 0) break; @@ -1352,6 +1463,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, retval = tty_ldisc_setup(tty, tty->link); if (retval) goto release_mem_out; + +#ifdef CONFIG_TTY_NOTIFIER + list_add(&tty->list, &tty_structs); + notify_tty_create(tty); +#endif return tty; fail_no_mem: @@ -1705,6 +1821,12 @@ int tty_release(struct inode *inode, struct file *filp) #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "freeing tty structure..."); #endif + +#ifdef CONFIG_TTY_NOTIFIER + notify_tty_release(tty); + tty_del(tty); +#endif + /* * Ask the line discipline code to release its structures */ @@ -2770,6 +2892,9 @@ void initialize_tty_struct(struct tty_struct *tty, spin_lock_init(&tty->read_lock); spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); +#ifdef CONFIG_TTY_NOTIFIER + INIT_LIST_HEAD(&tty->list); +#endif INIT_WORK(&tty->SAK_work, do_SAK_work); tty->driver = driver; diff --git a/include/linux/tty.h b/include/linux/tty.h index 4409967..7d57719 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -324,8 +325,29 @@ struct tty_struct { /* If the tty has a pending do_SAK, queue it here - akpm */ struct work_struct SAK_work; struct tty_port *port; +#ifdef CONFIG_TTY_NOTIFIER + struct list_head list; +#endif +}; + + +#ifdef CONFIG_TTY_NOTIFIER + +#define TTY_NOTIFY_DATA 1 +#define TTY_NOTIFY_CREATE 2 +#define TTY_NOTIFY_RELEASE 3 + +struct tty_notifier_param { + struct tty_struct *tty; + unsigned char *buf; + size_t size; }; +extern int register_tty_notifier(struct notifier_block *nb); +extern int unregister_tty_notifier(struct notifier_block *nb); + +#endif /* CONFIG_TTY_NOTIFIER */ + /* tty magic number */ #define TTY_MAGIC 0x5401 -- 1.6.6.1